diff options
Diffstat (limited to 'fbreader/src/network')
97 files changed, 11506 insertions, 0 deletions
diff --git a/fbreader/src/network/BookReference.cpp b/fbreader/src/network/BookReference.cpp new file mode 100644 index 0000000..9740a65 --- /dev/null +++ b/fbreader/src/network/BookReference.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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 <ZLFile.h> + +#include "BookReference.h" +#include "NetworkLinkCollection.h" + +BookReference::BookReference(const std::string &url, Format format, Type type) : URL(url), BookFormat(format), ReferenceType(type) { +} + +const std::string &BookReference::cleanURL() const { + return URL; +} + +std::string BuyBookReference::price(const std::string &price, const std::string ¤cy) { + if (currency.empty()) { + return price; + } else if (currency == "RUB") { + return price + " р."; + } else if (currency == "USD") { + return "$" + price; + } + return currency + " " + price; +} + +BuyBookReference::BuyBookReference(const std::string &url, Format format, Type type, const std::string &price) : BookReference(url, format, type), Price(price) { +} + +DecoratedBookReference::DecoratedBookReference(const BookReference &base, const std::string &url) : BookReference(url, base.BookFormat, base.ReferenceType), myCleanURL(base.cleanURL()) { +} + +const std::string &DecoratedBookReference::cleanURL() const { + return myCleanURL; +} + +std::string BookReference::localCopyFileName() const { + std::string fileName = NetworkLinkCollection::Instance().bookFileName(*this); + if (!fileName.empty() && ZLFile(fileName).exists()) { + return fileName; + } + + return std::string(); +} diff --git a/fbreader/src/network/BookReference.h b/fbreader/src/network/BookReference.h new file mode 100644 index 0000000..7b7ef74 --- /dev/null +++ b/fbreader/src/network/BookReference.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __BOOKREFERENCE_H__ +#define __BOOKREFERENCE_H__ + +#include <string> + +class BookReference { + +public: + enum Type { + DOWNLOAD_FULL, + DOWNLOAD_FULL_CONDITIONAL, + DOWNLOAD_DEMO, + DOWNLOAD_FULL_OR_DEMO, + BUY, + BUY_IN_BROWSER, + UNKNOWN + }; + + enum Format { + NONE = 0, + MOBIPOCKET = 1, + FB2_ZIP = 2, + EPUB = 3, + }; + +public: + BookReference(const std::string &url, Format format, Type type); + +public: + const std::string URL; + const Format BookFormat; + const Type ReferenceType; + +public: + virtual const std::string &cleanURL() const; + + std::string localCopyFileName() const; + +private: + BookReference(const BookReference&); + const BookReference &operator = (const BookReference&); +}; + +class BuyBookReference : public BookReference { + +public: + BuyBookReference(const std::string &url, Format format, Type type, const std::string &price); + +public: + static std::string price(const std::string &price, const std::string ¤cy); + +public: + const std::string Price; +}; + +class DecoratedBookReference : public BookReference { + +public: + DecoratedBookReference(const BookReference &base, const std::string &url); + +private: + const std::string &cleanURL() const; + +private: + const std::string myCleanURL; +}; + +#endif /* __BOOKREFERENCE_H__ */ diff --git a/fbreader/src/network/NetworkBookCollection.cpp b/fbreader/src/network/NetworkBookCollection.cpp new file mode 100644 index 0000000..155d702 --- /dev/null +++ b/fbreader/src/network/NetworkBookCollection.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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 <algorithm> + +#include <ZLResource.h> + +#include "NetworkBookCollection.h" + + +NetworkBookCollection::NetworkBookCollection() { + myAuthorComparator = new NetworkAuthorComparator(myAuthorRates); +} + +void NetworkBookCollection::clear() { + myBookList.clear(); + myAuthorRates.clear(); + myAuthorBooksMap.reset(); +} + +void NetworkBookCollection::addBook(shared_ptr<NetworkItem> bookPtr) { + if (bookPtr.isNull() || bookPtr->typeId() != NetworkBookItem::TYPE_ID) { + return; + } + myAuthorBooksMap.reset(); + + NetworkItem::List::iterator it = std::upper_bound(myBookList.begin(), myBookList.end(), bookPtr, NetworkBookItemComparator()); + myBookList.insert(it, bookPtr); + + NetworkBookItem &book = (NetworkBookItem &) *bookPtr; + + for (std::vector<NetworkBookItem::AuthorData>::const_iterator jt = book.Authors.begin(); jt != book.Authors.end(); ++jt) { + const NetworkBookItem::AuthorData &author = *jt; + std::map<NetworkBookItem::AuthorData, unsigned int>::iterator kt = myAuthorRates.find(author); + if (kt == myAuthorRates.end()) { + myAuthorRates[author] = book.Index; + } else if (kt->second > book.Index) { + kt->second = book.Index; + } + } +} + +const NetworkAuthorBooksMap &NetworkBookCollection::authorBooksMap() { + if (myAuthorBooksMap.isNull()) { + myAuthorBooksMap = new NetworkAuthorBooksMap(*myAuthorComparator); + NetworkAuthorBooksMap &bookMap = *myAuthorBooksMap; + for (NetworkItem::List::const_iterator it = myBookList.begin(); it != myBookList.end(); ++it) { + NetworkBookItem &book = (NetworkBookItem &) **it; + for (std::vector<NetworkBookItem::AuthorData>::const_iterator jt = book.Authors.begin(); jt != book.Authors.end(); ++jt) { + bookMap[*jt].push_back(*it); + } + } + } + return *myAuthorBooksMap; +} diff --git a/fbreader/src/network/NetworkBookCollection.h b/fbreader/src/network/NetworkBookCollection.h new file mode 100644 index 0000000..730416e --- /dev/null +++ b/fbreader/src/network/NetworkBookCollection.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __NETWORKBOOKCOLLECTION_H__ +#define __NETWORKBOOKCOLLECTION_H__ + +#include "NetworkItems.h" + +#include "NetworkComparators.h" + + +typedef std::map<NetworkBookItem::AuthorData, NetworkItem::List, NetworkAuthorComparator> NetworkAuthorBooksMap; + + +class NetworkBookCollection { + +public: + NetworkBookCollection(); + +public: + void addBook(shared_ptr<NetworkItem> bookPtr); + + const NetworkItem::List &books() const; + bool empty() const; + + void clear(); + + const NetworkAuthorBooksMap &authorBooksMap(); + +private: + NetworkItem::List myBookList; + std::map<NetworkBookItem::AuthorData, unsigned int> myAuthorRates; + shared_ptr<NetworkAuthorComparator> myAuthorComparator; + shared_ptr<NetworkAuthorBooksMap> myAuthorBooksMap; + +private: // disable copying + NetworkBookCollection(const NetworkBookCollection &); + const NetworkBookCollection &operator = (const NetworkBookCollection &); +}; + +inline const NetworkItem::List &NetworkBookCollection::books() const { return myBookList; } +inline bool NetworkBookCollection::empty() const { return myBookList.empty(); } + +#endif /* __NETWORKBOOKCOLLECTION_H__ */ diff --git a/fbreader/src/network/NetworkBookItem.cpp b/fbreader/src/network/NetworkBookItem.cpp new file mode 100644 index 0000000..5eeb101 --- /dev/null +++ b/fbreader/src/network/NetworkBookItem.cpp @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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 "NetworkItems.h" +#include "NetworkLink.h" +#include "authentication/NetworkAuthenticationManager.h" + +const ZLTypeId NetworkBookItem::TYPE_ID(NetworkItem::TYPE_ID); + +bool NetworkBookItem::AuthorData::operator < (const AuthorData &data) const { + const int sComp = SortKey.compare(data.SortKey); + return (sComp < 0) || (sComp == 0 && DisplayName < data.DisplayName); +} + +bool NetworkBookItem::AuthorData::operator != (const NetworkBookItem::AuthorData &data) const { + return DisplayName != data.DisplayName || SortKey != data.SortKey; +} + +bool NetworkBookItem::AuthorData::operator == (const NetworkBookItem::AuthorData &data) const { + return DisplayName == data.DisplayName && SortKey == data.SortKey; +} + +NetworkBookItem::NetworkBookItem( + const NetworkLink &link, + const std::string &id, + unsigned int index, + const std::string &title, + const std::string &summary, + const std::string &language, + const std::string &date, + const std::vector<AuthorData> &authors, + const std::vector<std::string> &tags, + const std::string &seriesTitle, + unsigned int indexInSeries, + const UrlInfoCollection &urlByType, + const std::vector<shared_ptr<BookReference> > references +) : + NetworkItem(link, title, summary, urlByType), + Index(index), + Id(id), + Language(language), + Date(date), + Authors(authors), + Tags(tags), + SeriesTitle(seriesTitle), + IndexInSeries(indexInSeries), + myReferences(references) { +} + +NetworkBookItem::NetworkBookItem(const NetworkBookItem &book, unsigned int index) : + NetworkItem(book.Link, book.Title, book.Summary, book.URLByType), + Index(index), + Id(book.Id), + Language(book.Language), + Date(book.Date), + Authors(book.Authors), + Tags(book.Tags), + SeriesTitle(book.SeriesTitle), + IndexInSeries(book.IndexInSeries) { +} + +const ZLTypeId &NetworkBookItem::typeId() const { + return TYPE_ID; +} + +shared_ptr<BookReference> NetworkBookItem::reference(BookReference::Type type) const { + shared_ptr<BookReference> reference; + for (std::vector<shared_ptr<BookReference> >::const_iterator it = myReferences.begin(); it != myReferences.end(); ++it) { + if ((*it)->ReferenceType == type && + (reference.isNull() || (*it)->BookFormat > reference->BookFormat)) { + reference = *it; + } + } + + if (reference.isNull() && type == BookReference::DOWNLOAD_FULL) { + reference = this->reference(BookReference::DOWNLOAD_FULL_CONDITIONAL); + if (!reference.isNull()) { + shared_ptr<NetworkAuthenticationManager> authManager = + Link.authenticationManager(); + if (authManager.isNull() || authManager->needPurchase(*this)) { + return 0; + } + reference = authManager->downloadReference(*this); + } + } + + if (reference.isNull() && + type == BookReference::DOWNLOAD_FULL && + this->reference(BookReference::BUY).isNull() && + this->reference(BookReference::BUY_IN_BROWSER).isNull()) { + reference = this->reference(BookReference::DOWNLOAD_FULL_OR_DEMO); + } + + if (reference.isNull() && + type == BookReference::DOWNLOAD_DEMO && + (!this->reference(BookReference::BUY).isNull() || + !this->reference(BookReference::BUY_IN_BROWSER).isNull())) { + reference = this->reference(BookReference::DOWNLOAD_FULL_OR_DEMO); + } + + return reference; +} + +std::string NetworkBookItem::localCopyFileName() const { + const bool hasBuyReference = + !this->reference(BookReference::BUY).isNull() || + !this->reference(BookReference::BUY_IN_BROWSER).isNull(); + shared_ptr<BookReference> reference; + std::string fileName; + for (std::vector<shared_ptr<BookReference> >::const_iterator it = myReferences.begin(); it != myReferences.end(); ++it) { + const BookReference::Type type = (*it)->ReferenceType; + if ((type == BookReference::DOWNLOAD_FULL || + type == BookReference::DOWNLOAD_FULL_CONDITIONAL || + (!hasBuyReference && type == BookReference::DOWNLOAD_FULL_OR_DEMO)) && + (reference.isNull() || (*it)->BookFormat > reference->BookFormat)) { + std::string name = (*it)->localCopyFileName(); + if (!name.empty()) { + reference = *it; + fileName = name; + } + } + } + return fileName; +} + +void NetworkBookItem::removeLocalFiles() const { + const bool hasBuyReference = + !this->reference(BookReference::BUY).isNull() || + !this->reference(BookReference::BUY_IN_BROWSER).isNull(); + for (std::vector<shared_ptr<BookReference> >::const_iterator it = myReferences.begin(); it != myReferences.end(); ++it) { + const BookReference::Type type = (*it)->ReferenceType; + if (type == BookReference::DOWNLOAD_FULL || + type == BookReference::DOWNLOAD_FULL_CONDITIONAL || + (!hasBuyReference && type == BookReference::DOWNLOAD_FULL_OR_DEMO)) { + std::string fileName = (*it)->localCopyFileName(); + if (!fileName.empty()) { + // TODO: remove a book from the library + // TODO: remove a record from the database + ZLFile(fileName).remove(); + } + } + } +} + +bool NetworkBookItem::isFullyLoaded() const { + return true; +} + +void NetworkBookItem::loadFullInformation(shared_ptr<ZLNetworkRequest::Listener> listener) { + listener->finished(); +} + +std::vector<shared_ptr<NetworkItem> > NetworkBookItem::getRelatedCatalogsItems() const { + return std::vector<shared_ptr<NetworkItem> >(); +} + +void NetworkBookItem::updateReferences(const std::vector<shared_ptr<BookReference> > &references) { + //TODO implement using one UrlInfoCollection instead of vector of references and urlByType + for (std::size_t i = 0; i < references.size(); ++i) { + bool found = false; + const shared_ptr<BookReference> newRef = references.at(i); + for (std::size_t j = 0; j < myReferences.size(); ++j) { + shared_ptr<BookReference> ref = myReferences.at(j); + if (ref->ReferenceType == newRef->ReferenceType && ref->BookFormat == ref->BookFormat) { + //TODO maybe implement a supporting of new urls with same book format & reference type: + //ref->URL = newRef->URL; + found = true; + break; + } + } + if (!found) { + myReferences.push_back(newRef); + } + } +} diff --git a/fbreader/src/network/NetworkCatalogItem.cpp b/fbreader/src/network/NetworkCatalogItem.cpp new file mode 100644 index 0000000..58c739c --- /dev/null +++ b/fbreader/src/network/NetworkCatalogItem.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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 "authentication/NetworkAuthenticationManager.h" +#include "NetworkLink.h" + +#include "NetworkItems.h" + +const ZLTypeId NetworkCatalogItem::TYPE_ID(NetworkItem::TYPE_ID); + +NetworkCatalogItem::NetworkCatalogItem( + const NetworkLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility, + int flags +) : + NetworkItem(link, title, summary, urlByType), + myAccessibility(accessibility), + myFlags(flags) + { +} + +const ZLTypeId &NetworkCatalogItem::typeId() const { + return TYPE_ID; +} + +void NetworkCatalogItem::onDisplayItem() { +} + +bool NetworkCatalogItem::supportsResumeLoading() { + return false; +} + +std::string NetworkCatalogItem::resumeLoading(NetworkItem::List &/*children*/, shared_ptr<ZLNetworkRequest::Listener> listener) { + listener->finished(); + return std::string(); +} + +std::string NetworkCatalogItem::getCatalogUrl() { + return URLByType[URL_CATALOG]; +} + +int NetworkCatalogItem::getFlags() const { + return myFlags; +} + +NetworkCatalogItem::AccessibilityType NetworkCatalogItem::getAccessibility() const { + return myAccessibility; +} + +ZLBoolean3 NetworkCatalogItem::getVisibility() const { + shared_ptr<NetworkAuthenticationManager> mgr = Link.authenticationManager(); + switch (myAccessibility) { + case ALWAYS: + return B3_TRUE; + case SIGNED_IN: + if (mgr.isNull()) { + return B3_FALSE; + } + return mgr->isAuthorised().Status == B3_TRUE ? B3_TRUE : B3_UNDEFINED; + case HAS_BOOKS: + if (mgr.isNull()) { + return B3_FALSE; + } else { + if (mgr->purchasedBooks().size() > 0) { + return B3_TRUE; + } else { + return B3_FALSE; + } + } + } + return B3_FALSE; +} diff --git a/fbreader/src/network/NetworkComparators.cpp b/fbreader/src/network/NetworkComparators.cpp new file mode 100644 index 0000000..66a0de3 --- /dev/null +++ b/fbreader/src/network/NetworkComparators.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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 "NetworkComparators.h" + +bool NetworkBookItemComparator::operator () (const shared_ptr<NetworkItem> &bookPtr0, const shared_ptr<NetworkItem> &bookPtr1) const { + const bool book0isABook = + bookPtr0->isInstanceOf(NetworkBookItem::TYPE_ID); + const bool book1isABook = + bookPtr1->isInstanceOf(NetworkBookItem::TYPE_ID); + + if (!book0isABook && !book1isABook) { + return bookPtr0->Title < bookPtr1->Title; + } + if (!book0isABook || !book1isABook) { + return !book0isABook; + } + + const NetworkBookItem &book0 = (NetworkBookItem &) *bookPtr0; + const NetworkBookItem &book1 = (NetworkBookItem &) *bookPtr1; + + const std::vector<NetworkBookItem::AuthorData> &authors0 = book0.Authors; + const std::vector<NetworkBookItem::AuthorData> &authors1 = book1.Authors; + if (authors0.empty() && !authors1.empty()) { + return true; + } + if (authors1.empty() && !authors0.empty()) { + return false; + } + if (!authors0.empty() && !authors1.empty()) { + if (authors0.front().SortKey != authors1.front().SortKey) { + return authors0.front().SortKey < authors1.front().SortKey; + } + } + + /*if (book0.Index != book1.Index) { + return book0.Index < book1.Index; + }*/ + + const bool book0HasSeriesTitle = !book0.SeriesTitle.empty(); + const bool book1HasSeriesTitle = !book1.SeriesTitle.empty(); + if (book0HasSeriesTitle && book1HasSeriesTitle) { + const int comp = book0.SeriesTitle.compare(book1.SeriesTitle); + if (comp != 0) { + return comp < 0; + } else { + int diff = book0.IndexInSeries - book1.IndexInSeries; + if (diff != 0) { + return diff < 0; + } + } + return book0.Title < book1.Title; + } + + const std::string &book0Key = book0HasSeriesTitle ? book0.SeriesTitle : book0.Title; + const std::string &book1Key = book1HasSeriesTitle ? book1.SeriesTitle : book1.Title; + const int comp = book0Key.compare(book1Key); + if (comp != 0) { + return comp < 0; + } + return book1HasSeriesTitle; +} + + +NetworkAuthorComparator::NetworkAuthorComparator(const std::map<NetworkBookItem::AuthorData, unsigned int> &rates) : myRates(rates) { +} + +bool NetworkAuthorComparator::operator () (const NetworkBookItem::AuthorData &author0, const NetworkBookItem::AuthorData &author1) const { + std::map<NetworkBookItem::AuthorData, unsigned int>::const_iterator it1 = myRates.find(author0); + std::map<NetworkBookItem::AuthorData, unsigned int>::const_iterator it2 = myRates.find(author1); + if (it1 == myRates.end() && it2 == myRates.end()) { + return author0 < author1; + } + if (it1 == myRates.end()) { + return false; + } + if (it2 == myRates.end()) { + return true; + } + if (it1->second != it2->second) { + return it1->second < it2->second; + } + return author0 < author1; +} + +bool NetworkBookItemByTitleComparator::operator ()(const shared_ptr<NetworkItem> &bookPtr0, const shared_ptr<NetworkItem> &bookPtr1) const { + return bookPtr0->Title < bookPtr1->Title; +} + +bool NetworkBookItemBySeriesComparator::operator ()(const shared_ptr<NetworkItem> &bookPtr0, const shared_ptr<NetworkItem> &bookPtr1) const { + const NetworkBookItem &book0 = static_cast<const NetworkBookItem&>(*bookPtr0); + const NetworkBookItem &book1 = static_cast<const NetworkBookItem&>(*bookPtr1); + if (book0.SeriesTitle != book1.SeriesTitle) { + return book0.SeriesTitle < book1.SeriesTitle; + } + const int diff = book0.IndexInSeries - book1.IndexInSeries; + if (diff != 0) { + return diff < 0 ? true : false; + } + return book0.Title < book1.Title; +} + + + diff --git a/fbreader/src/network/NetworkComparators.h b/fbreader/src/network/NetworkComparators.h new file mode 100644 index 0000000..a872a3f --- /dev/null +++ b/fbreader/src/network/NetworkComparators.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __NETWORKCOMPARATORS_H__ +#define __NETWORKCOMPARATORS_H__ + + +#include <map> + +#include "NetworkItems.h" + +class NetworkBookItemComparator { + +public: + bool operator () (const shared_ptr<NetworkItem> &bookPtr0, const shared_ptr<NetworkItem> &bookPtr1) const; +}; + +class NetworkBookItemByTitleComparator { + +public: + bool operator () (const shared_ptr<NetworkItem> &bookPtr0, const shared_ptr<NetworkItem> &bookPtr1) const; +}; + +class NetworkBookItemBySeriesComparator { + +public: + bool operator () (const shared_ptr<NetworkItem> &bookPtr0, const shared_ptr<NetworkItem> &bookPtr1) const; +}; + +class NetworkAuthorComparator { + +public: + NetworkAuthorComparator(const std::map<NetworkBookItem::AuthorData, unsigned int> &rates); + + bool operator () (const NetworkBookItem::AuthorData &author0, const NetworkBookItem::AuthorData &author1) const; + +private: + const std::map<NetworkBookItem::AuthorData, unsigned int> &myRates; +}; + +#endif /* __NETWORKCOMPARATORS_H__ */ diff --git a/fbreader/src/network/NetworkErrors.cpp b/fbreader/src/network/NetworkErrors.cpp new file mode 100644 index 0000000..d20546f --- /dev/null +++ b/fbreader/src/network/NetworkErrors.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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 <ZLResource.h> +#include <ZLStringUtil.h> +#include <ZLDialogManager.h> + +#include "NetworkErrors.h" + +const std::string NetworkErrors::ERROR_AUTHENTICATION_FAILED = "authenticationFailed"; +const std::string NetworkErrors::ERROR_INTERNAL = "internalError"; +const std::string NetworkErrors::ERROR_PURCHASE_NOT_ENOUGH_MONEY = "purchaseNotEnoughMoney"; +const std::string NetworkErrors::ERROR_PURCHASE_MISSING_BOOK = "purchaseMissingBook"; +const std::string NetworkErrors::ERROR_PURCHASE_ALREADY_PURCHASED = "purchaseAlreadyPurchased"; +const std::string NetworkErrors::ERROR_BOOK_NOT_PURCHASED = "bookNotPurchased"; +const std::string NetworkErrors::ERROR_DOWNLOAD_LIMIT_EXCEEDED = "downloadLimitExceeded"; + +const std::string NetworkErrors::ERROR_LOGIN_ALREADY_TAKEN = "loginAlreadyTaken"; +const std::string NetworkErrors::ERROR_LOGIN_WAS_NOT_SPECIFIED = "loginNotSpecified"; +const std::string NetworkErrors::ERROR_PASSWORD_WAS_NOT_SPECIFIED = "passwordNotSpecified"; +const std::string NetworkErrors::ERROR_EMAIL_WAS_NOT_SPECIFIED = "emailNotSpecified"; +const std::string NetworkErrors::ERROR_INVALID_EMAIL = "invalidEMail"; +const std::string NetworkErrors::ERROR_TOO_MANY_REGISTRATIONS = "tooManyRegistrations"; + +const std::string NetworkErrors::ERROR_NO_USER_EMAIL = "noUserEmail"; + +const std::string NetworkErrors::ERROR_SOMETHING_WRONG = "somethingWrongMessage"; +const std::string NetworkErrors::ERROR_UNSUPPORTED_OPERATION = "unsupportedOperation"; + +const std::string NetworkErrors::ERROR_CANT_DOWNLOAD_LIBRARIES_LIST = "librariesListDownloadingFailed"; +const std::string NetworkErrors::ERROR_TIMEOUT_EXPIRED = "operationTimedOutMessage"; + + +std::string NetworkErrors::errorMessage(const std::string &error) { + if (error.empty()) { + return ""; + } + + const ZLResource &errorResource = ZLResource::resource("dialog")["networkError"]; + return errorResource[error].value(); +} + +std::string NetworkErrors::errorMessage(const std::string &error, const std::string &arg0) { + if (error.empty()) { + return ""; + } + const ZLResource &errorResource = ZLResource::resource("dialog")["networkError"]; + return ZLStringUtil::printf(errorResource[error].value(), arg0); +} + +void NetworkErrors::showErrorMessage(const std::string &error) { + ZLDialogManager::Instance().errorBox(ZLResourceKey("networkError"), error); +} + diff --git a/fbreader/src/network/NetworkErrors.h b/fbreader/src/network/NetworkErrors.h new file mode 100644 index 0000000..d18d2f0 --- /dev/null +++ b/fbreader/src/network/NetworkErrors.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __NETWORKERRORS_H__ +#define __NETWORKERRORS_H__ + +#include <string> + +class NetworkErrors { + +private: // disable instantiation + NetworkErrors(); + +public: + static const std::string ERROR_AUTHENTICATION_FAILED; + static const std::string ERROR_INTERNAL; + static const std::string ERROR_PURCHASE_NOT_ENOUGH_MONEY; + static const std::string ERROR_PURCHASE_MISSING_BOOK; + static const std::string ERROR_PURCHASE_ALREADY_PURCHASED; + static const std::string ERROR_BOOK_NOT_PURCHASED; + static const std::string ERROR_DOWNLOAD_LIMIT_EXCEEDED; + + static const std::string ERROR_LOGIN_ALREADY_TAKEN; + static const std::string ERROR_LOGIN_WAS_NOT_SPECIFIED; + static const std::string ERROR_PASSWORD_WAS_NOT_SPECIFIED; + static const std::string ERROR_EMAIL_WAS_NOT_SPECIFIED; + static const std::string ERROR_INVALID_EMAIL; + static const std::string ERROR_TOO_MANY_REGISTRATIONS; + + static const std::string ERROR_NO_USER_EMAIL; + + static const std::string ERROR_SOMETHING_WRONG; + static const std::string ERROR_UNSUPPORTED_OPERATION; + static const std::string ERROR_CANT_DOWNLOAD_LIBRARIES_LIST; + + static const std::string ERROR_TIMEOUT_EXPIRED; + +public: + static std::string errorMessage(const std::string &error); + static std::string errorMessage(const std::string &error, const std::string &arg0); + static void showErrorMessage(const std::string &error); +}; + +#endif /* __NETWORKERRORS_H__ */ diff --git a/fbreader/src/network/NetworkItem.cpp b/fbreader/src/network/NetworkItem.cpp new file mode 100644 index 0000000..33e22c4 --- /dev/null +++ b/fbreader/src/network/NetworkItem.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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 "NetworkItems.h" + +const ZLTypeId NetworkItem::TYPE_ID(ZLObjectWithRTTI::TYPE_ID); + +NetworkItem::NetworkItem( + const NetworkLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType +) : + Link(link), + Title(title), + Summary(summary), + URLByType(urlByType) { +} + +NetworkItem::~NetworkItem() { +} diff --git a/fbreader/src/network/NetworkItems.h b/fbreader/src/network/NetworkItems.h new file mode 100644 index 0000000..169e5b7 --- /dev/null +++ b/fbreader/src/network/NetworkItems.h @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __NETWORKITEMS_H__ +#define __NETWORKITEMS_H__ + +#include <string> +#include <vector> +#include <map> + +#include <shared_ptr.h> + +#include <ZLFile.h> +#include <ZLTypeId.h> +#include <ZLBoolean3.h> +#include <ZLNetworkRequest.h> + +#include <ZLTreeNode.h> + +#include "BookReference.h" + +class NetworkAuthenticationManager; +class NetworkLink; + +class NetworkItem : public ZLObjectWithRTTI { + +public: + typedef std::vector<shared_ptr<NetworkItem> > List; + + enum URLType { + URL_NONE, + URL_CATALOG, + URL_HTML_PAGE, + URL_COVER, + URL_FULL_COVER, + URL_SINGLE_ENTRY + }; + + typedef std::map<URLType,std::string> UrlInfoCollection; + +protected: + static const ZLTypeId TYPE_ID; + +protected: + NetworkItem( + const NetworkLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType + ); + +public: + virtual ~NetworkItem(); + + virtual const ZLTypeId &typeId() const = 0; + +public: + const NetworkLink &Link; + const std::string Title; + /*const*/ std::string Summary; + /*const*/ UrlInfoCollection URLByType; + +private: // disable copying + NetworkItem(const NetworkItem &item); + const NetworkItem &operator = (const NetworkItem &); +}; + +class NetworkCatalogItem : public NetworkItem { + +public: + static const ZLTypeId TYPE_ID; + + enum AccessibilityType { + ALWAYS, + SIGNED_IN, + HAS_BOOKS + }; + + enum CatalogFlags { + FLAG_NONE = 0, + FLAG_SHOW_AUTHOR = 1 << 0, + FLAG_GROUP_BY_AUTHOR = 1 << 1, + FLAG_GROUP_BY_SERIES = 1 << 2, + FLAG_GROUP_MORE_THAN_1_BOOK_BY_SERIES = 1 << 3, + FLAGS_DEFAULT = + FLAG_SHOW_AUTHOR | + FLAG_GROUP_MORE_THAN_1_BOOK_BY_SERIES, + FLAGS_GROUP = + FLAG_GROUP_BY_AUTHOR | + FLAG_GROUP_BY_SERIES | + FLAG_GROUP_MORE_THAN_1_BOOK_BY_SERIES, + }; + +public: + NetworkCatalogItem( + const NetworkLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility = ALWAYS, + int flags = FLAGS_DEFAULT + ); + + const ZLTypeId &typeId() const; + + // method is called each time the View Node is created for the Item. + virtual void onDisplayItem(); + // returns error message + virtual std::string loadChildren(List &children, shared_ptr<ZLNetworkRequest::Listener> listener = 0) = 0; + virtual bool supportsResumeLoading(); + virtual std::string resumeLoading(List &children, shared_ptr<ZLNetworkRequest::Listener> listener = 0); + + int getFlags() const; + AccessibilityType getAccessibility() const; + ZLBoolean3 getVisibility() const; + +protected: + virtual std::string getCatalogUrl(); + +private: + const AccessibilityType myAccessibility; + const int myFlags; +}; + +class NetworkBookItem : public NetworkItem { + +public: + struct AuthorData { + std::string DisplayName; + std::string SortKey; + + bool operator < (const AuthorData &data) const; + bool operator != (const AuthorData &data) const; + bool operator == (const AuthorData &data) const; + }; + +public: + static const ZLTypeId TYPE_ID; + +public: + NetworkBookItem( + const NetworkLink &link, + const std::string &id, + unsigned int index, + const std::string &title, + const std::string &summary, + const std::string &language, + const std::string &date, + const std::vector<AuthorData> &authors, + const std::vector<std::string> &tags, + const std::string &seriesTitle, + unsigned int indexInSeries, + const UrlInfoCollection &urlByType, + const std::vector<shared_ptr<BookReference> > references + ); + NetworkBookItem(const NetworkBookItem &book, unsigned int index); + + const ZLTypeId &typeId() const; + +public: + shared_ptr<BookReference> reference(BookReference::Type type) const; + + std::string localCopyFileName() const; + void removeLocalFiles() const; + + virtual bool isFullyLoaded() const; + virtual void loadFullInformation(shared_ptr<ZLNetworkRequest::Listener> listener); + virtual std::vector<shared_ptr<NetworkItem> > getRelatedCatalogsItems() const; + + void updateReferences(const std::vector<shared_ptr<BookReference> > &references); + +public: + /*const*/ unsigned int Index; + const std::string Id; + const std::string Language; + const std::string Date; + const std::vector<AuthorData> Authors; + const std::vector<std::string> Tags; + const std::string SeriesTitle; + const int IndexInSeries; + +private: + std::vector<shared_ptr<BookReference> > myReferences; +}; + +#endif /* __NETWORKITEMS_H__ */ diff --git a/fbreader/src/network/NetworkLink.cpp b/fbreader/src/network/NetworkLink.cpp new file mode 100644 index 0000000..218de23 --- /dev/null +++ b/fbreader/src/network/NetworkLink.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <[email protected]> + * + * 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 <ZLNetworkRequest.h> + +#include <ZLibrary.h> +#include <ZLFile.h> +#include <ZLStringUtil.h> + +#include "NetworkLink.h" +#include "NetworkOperationData.h" + +const std::string NetworkLink::URL_MAIN = "main"; +const std::string NetworkLink::URL_SEARCH = "search"; +const std::string NetworkLink::URL_SIGN_IN = "signIn"; +const std::string NetworkLink::URL_SIGN_OUT = "signOut"; +const std::string NetworkLink::URL_SIGN_UP = "signUp"; +const std::string NetworkLink::URL_TOPUP = "topup"; +const std::string NetworkLink::URL_RECOVER_PASSWORD = "recoverPassword"; + +NetworkLink::NetworkLink( + const std::string &siteName +) : + mySiteName(ZLStringUtil::stringStartsWith(siteName, "www.") ? siteName.substr(std::string("www.").length()) : siteName), + myEnabled(true), + myUpdated(0) { +} + +NetworkLink::~NetworkLink() { +} + +std::string NetworkLink::url(const std::string &urlId) const { + std::map<std::string,std::string>::const_iterator it = myLinks.find(urlId); + return (it != myLinks.end()) ? it->second : std::string(); +} + +shared_ptr<ZLNetworkRequest> NetworkLink::resume(NetworkOperationData &result) const { + result.clear(); + return 0; +} + +void NetworkLink::setTitle(const std::string& title) { + myTitle = title; +} +void NetworkLink::setSummary(const std::string& summary) { + mySummary = summary; +} + +void NetworkLink::setLanguage(const std::string &language) { + myLanguage = language; +} + +void NetworkLink::setIcon(const std::string& icon) { + myIcon = icon; +} + +void NetworkLink::setPredefinedId(const std::string& id) { + myPredefinedId = id; +} + +void NetworkLink::setLinks(const std::map<std::string,std::string>& links) { + myLinks = links; +} + +void NetworkLink::setUpdated(shared_ptr<ATOMUpdated> u) { + myUpdated = u; +} + +std::string NetworkLink::getSiteName() const { + return mySiteName; +} + +void NetworkLink::setEnabled(bool enabled) { + myEnabled = enabled; +} + +std::string NetworkLink::getTitle() const { + return myTitle; +} +std::string NetworkLink::getSummary() const { + return mySummary; +} + +std::string NetworkLink::getLanguage() const { + return myLanguage; +} + +std::string NetworkLink::getPredefinedId() const { + return myPredefinedId; +} + +const std::map<std::string,std::string>& NetworkLink::getLinks() const { + return myLinks; +} + +shared_ptr<ATOMUpdated> NetworkLink::getUpdated() const { + return myUpdated; +} + +bool NetworkLink::isPredefined() const { + return !myPredefinedId.empty(); +} + +std::string NetworkLink::getIcon() const { + return myIcon; +} +bool NetworkLink::isEnabled() const { + return myEnabled; +} + +void NetworkLink::loadFrom(const NetworkLink & link) { + myTitle = link.myTitle; + myIcon = link.myIcon; + mySummary = link.mySummary; + myLanguage = link.myLanguage; + myLinks = link.myLinks; + myPredefinedId = link.myPredefinedId; + myUpdated = link.myUpdated; +} + +void NetworkLink::loadLinksFrom(const NetworkLink & link) { + myIcon = link.myIcon; + myLinks = link.myLinks; + myUpdated = link.myUpdated; +} + +void NetworkLink::loadSummaryFrom(const NetworkLink & link) { + myTitle = link.myTitle; + mySummary = link.mySummary; +} diff --git a/fbreader/src/network/NetworkLink.h b/fbreader/src/network/NetworkLink.h new file mode 100644 index 0000000..e0260b0 --- /dev/null +++ b/fbreader/src/network/NetworkLink.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __NETWORKLINK_H__ +#define __NETWORKLINK_H__ + +#include <string> +#include <vector> +#include <map> + +#include <shared_ptr.h> +#include <ZLOptions.h> + +#include "NetworkItems.h" +#include "atom/ATOMMetadata.h" + +class ZLNetworkRequest; + +class NetworkOperationData; +class NetworkAuthenticationManager; + +class NetworkLink { + +public: + static const std::string URL_MAIN; + static const std::string URL_SEARCH; + static const std::string URL_SIGN_IN; + static const std::string URL_SIGN_OUT; + static const std::string URL_SIGN_UP; + static const std::string URL_TOPUP; + static const std::string URL_RECOVER_PASSWORD; + +protected: + NetworkLink( + const std::string &siteName + ); + +public: + virtual ~NetworkLink(); + std::string url(const std::string &urlId) const; + + void setTitle(const std::string& title); + void setSummary(const std::string& summary); + void setLanguage(const std::string& language); + void setIcon(const std::string& icon); + void setLinks(const std::map<std::string,std::string>& links); + void setPredefinedId(const std::string& id); + void setEnabled(bool enabled); + void setUpdated(shared_ptr<ATOMUpdated> u); + + std::string getSiteName() const; + std::string getTitle() const; + std::string getSummary() const; + std::string getLanguage() const; + std::string getIcon() const; + const std::map<std::string,std::string>& getLinks() const; + std::string getPredefinedId() const; + bool isEnabled() const; + shared_ptr<ATOMUpdated> getUpdated() const; + + bool isPredefined() const; + + void loadFrom(const NetworkLink & link); + void loadLinksFrom(const NetworkLink & link); + void loadSummaryFrom(const NetworkLink & link); + +public: + virtual shared_ptr<ZLNetworkRequest> simpleSearchData(NetworkOperationData &data, const std::string &pattern) const = 0; + virtual shared_ptr<ZLNetworkRequest> advancedSearchData(NetworkOperationData &data, const std::string &titleAndSeries, const std::string &author, const std::string &tag, const std::string &annotation) const = 0; + virtual shared_ptr<ZLNetworkRequest> resume(NetworkOperationData &data) const; + + virtual shared_ptr<NetworkAuthenticationManager> authenticationManager() const = 0; + virtual shared_ptr<NetworkItem> libraryItem() const = 0; + + virtual void rewriteUrl(std::string &url, bool isUrlExternal = false) const = 0; + +private: + const std::string mySiteName; + std::string myTitle; + std::string myIcon; + std::string mySummary; + std::string myLanguage; + std::map<std::string,std::string> myLinks; + std::string myPredefinedId; + bool myEnabled; + shared_ptr<ATOMUpdated> myUpdated; + +private: // disable copying + NetworkLink(const NetworkLink &); + const NetworkLink &operator = (const NetworkLink &); +}; + +#endif /* __NETWORKLINK_H__ */ diff --git a/fbreader/src/network/NetworkLinkCollection.cpp b/fbreader/src/network/NetworkLinkCollection.cpp new file mode 100644 index 0000000..0b530b0 --- /dev/null +++ b/fbreader/src/network/NetworkLinkCollection.cpp @@ -0,0 +1,561 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <[email protected]> + * + * 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 <cctype> +#include <algorithm> + +#include <ZLFile.h> +#include <ZLDir.h> +#include <ZLStringUtil.h> +#include <ZLUnicodeUtil.h> +#include <ZLResource.h> +#include <ZLNetworkManager.h> +#include <ZLTimeManager.h> +#include <ZLNetworkUtil.h> +#include <ZLibrary.h> +#include <ZLDialogManager.h> +#include <ZLInputStream.h> +#include <ZLOutputStream.h> +#include "../fbreader/FBReader.h" +#include "../networkActions/NetworkOperationRunnable.h" + +#include "NetworkLinkCollection.h" + +#include "../options/FBCategoryKey.h" + +#include "../database/networkdb/NetworkDB.h" + +#include "NetworkOperationData.h" +#include "NetworkBookCollection.h" +#include "BookReference.h" +#include "NetworkErrors.h" + +#include "opds/OPDSLink.h" +#include "opds/OPDSLink_GenericXMLParser.h" +#include "opds/OPDSLink_GenericFeedReader.h" +#include "opds/OPDSXMLParser.h" + +#include "opds/URLRewritingRule.h" + +NetworkLinkCollection *NetworkLinkCollection::ourInstance = 0; + +NetworkLinkCollection &NetworkLinkCollection::Instance() { + if (ourInstance == 0) { + ourInstance = new NetworkLinkCollection(); + } + return *ourInstance; +} + +class NetworkLinkCollection::Comparator { + +public: + bool operator() ( + const shared_ptr<NetworkLink> &first, + const shared_ptr<NetworkLink> &second + ) const; + +private: + std::string removeLeadingNonAscii(const std::string &title) const; +}; + +std::string NetworkLinkCollection::Comparator::removeLeadingNonAscii(const std::string &title) const { + std::string str = title; + std::string::iterator it = str.begin(); + for (; it != str.end(); ++it) { + if ((*it & 0x80) == 0 && std::isalnum(*it)) { + break; + } + } + if (it != str.end()) { + str.erase(str.begin(), it); + } + return str; +} + +bool NetworkLinkCollection::Comparator::operator() ( + const shared_ptr<NetworkLink> &first, + const shared_ptr<NetworkLink> &second +) const { + return + removeLeadingNonAscii(first->getSiteName()) < + removeLeadingNonAscii(second->getSiteName()); +} + +//void NetworkLinkCollection::deleteLink(NetworkLink& link) { +// BooksDB::Instance().deleteNetworkLink(link.SiteName); +// for (std::vector<shared_ptr<NetworkLink> >::iterator it = myLinks.begin(); it != myLinks.end(); ++it) { +// if (&(**it) == &link) { +// myLinks.erase(it); +// break; +// } +// } +// FBReader::Instance().refreshWindow(); +//} + +//void NetworkLinkCollection::saveLink(NetworkLink& link, bool isAuto) { +// saveLinkWithoutRefreshing(link, isAuto); +// FBReader::Instance().refreshWindow(); +//} + +void NetworkLinkCollection::addOrUpdateLink(shared_ptr<NetworkLink> link) { + bool found = false; + bool updated = false; + + for (std::size_t i = 0; i < myLinks.size(); ++i) { + shared_ptr<NetworkLink> curLink = myLinks.at(i); + if (curLink->getPredefinedId() == link->getPredefinedId()) { + //if (*(link->getUpdated()) > *(curLink->getUpdated())) { + myLinks.at(i) = link; + updated = true; + //TODO implement custom links saving + found = true; + break; + } + } + + if (!found) { + myLinks.push_back(link); + std::sort(myLinks.begin(), myLinks.end(), Comparator()); + updated = true; + } + if (updated) { + NetworkDB::Instance().saveNetworkLink(link); + //FBReader::Instance().sendRefresh(); + } +} + + + +static const std::string LOADING_NETWORK_LIBRARY_LIST = "loadingNetworkLibraryList"; + +class NetworkDownloadListRunnable : public NetworkOperationRunnable { +public: + NetworkDownloadListRunnable(ZLFile &tmpFile, const std::string &genericUrl) : + NetworkOperationRunnable(LOADING_NETWORK_LIBRARY_LIST), + myTmpFile(tmpFile), + myGenericUrl(genericUrl) { + } + +private: + void run() { + shared_ptr<ZLNetworkRequest> loadingRequest = ZLNetworkManager::Instance().createDownloadRequest(myGenericUrl, myTmpFile.physicalFilePath()); + myErrorMessage = ZLNetworkManager::Instance().perform(loadingRequest); + } + +private: + ZLFile &myTmpFile; + std::string myGenericUrl; +}; + + +class NetworkLinksUpdater : public ZLRunnable { + +public: + NetworkLinksUpdater(NetworkLinkCollection &networkLinkCollection, shared_ptr<ZLFile> genericFile) : + myNetworkLinkCollection(networkLinkCollection), myGenericFile(genericFile) { } + +private: + void run() { + std::vector<shared_ptr<NetworkLink> > links; + shared_ptr<OPDSFeedReader> feedReader = new OPDSLink::GenericFeedReader(links); + shared_ptr<ZLXMLReader> parser = new OPDSLink::GenericXMLParser(feedReader); + parser->readDocument(*myGenericFile); + + for (std::vector<shared_ptr<NetworkLink> >::iterator it = links.begin(); it != links.end(); ++it) { + myNetworkLinkCollection.addOrUpdateLink(*it); + } + } + +private: + NetworkLinkCollection &myNetworkLinkCollection; + shared_ptr<ZLFile> myGenericFile; +}; + + +NetworkLinkCollection::NetworkLinkCollection() : + DirectoryOption(ZLCategoryKey::NETWORK, "Options", "DownloadDirectory", ""), + LastUpdateTimeOption(ZLCategoryKey::NETWORK, "Update", "LastUpdateTime", -1), + myIsInitialized(false) { +} + +class NetworkLinkCollectionSynchronizer : public DBRunnable { +public: + NetworkLinkCollectionSynchronizer(NetworkLinkCollection &collection) : myCollection(collection) {} + bool run() { + myCollection.synchronize(); + return true; + } +private: + NetworkLinkCollection &myCollection; +}; + +void NetworkLinkCollection::initialize() { + if (myIsInitialized) { + return; + } + NetworkLinkCollectionSynchronizer runnable(*this); + NetworkDB::Instance().executeAsTransaction(runnable); +} + +void NetworkLinkCollection::synchronize() { + NetworkDB::Instance().loadNetworkLinks(myLinks); + std::sort(myLinks.begin(), myLinks.end(), Comparator()); + updateLinks("http://data.fbreader.org/catalogs/generic-1.9.xml"); +} + +void NetworkLinkCollection::updateLinks(std::string genericUrl) { + shared_ptr<ZLFile> genericFile = getGenericFile(genericUrl); + if (genericFile.isNull()) { + NetworkErrors::showErrorMessage(NetworkErrors::errorMessage(NetworkErrors::ERROR_CANT_DOWNLOAD_LIBRARIES_LIST)); + return; + } + + NetworkLinksUpdater updater(*this, genericFile); + ZLDialogManager::Instance().wait(ZLResourceKey(LOADING_NETWORK_LIBRARY_LIST), updater); + myIsInitialized = true; +} + +shared_ptr<ZLFile> NetworkLinkCollection::getGenericFile(std::string genericUrl) { + const std::string FILE_NAME = "fbreader_catalogs-" + genericUrl.substr(genericUrl.find_last_of('/') + 1); + ZLFile genericFileDir(ZLNetworkManager::CacheDirectory()); + genericFileDir.directory(true); + shared_ptr<ZLFile> genericFile = new ZLFile(ZLNetworkManager::CacheDirectory() + ZLibrary::FileNameDelimiter + FILE_NAME); + + long diff = LastUpdateTimeOption.value() == -1 ? -1 : ZLTime().millisecondsFrom(ZLTime(LastUpdateTimeOption.value(), 0)); + + if (genericFile->exists() && diff != -1 && diff < 7 * 24 * 60 * 60 * 1000) { //1 week + return genericFile; + } + + ZLFile tmpFile(ZLNetworkManager::CacheDirectory() + ZLibrary::FileNameDelimiter + "tmp" + FILE_NAME); + NetworkDownloadListRunnable runnable(tmpFile, genericUrl); + runnable.executeWithUI(); + if (runnable.hasErrors()) { + if (!genericFile->exists()) { //loading list from saved file even if obsolete + return 0; + } else { + return genericFile; + } + } + + shared_ptr<ZLOutputStream> outputStream = genericFile->outputStream(true); + shared_ptr<ZLInputStream> inputStream = tmpFile.inputStream(); + if (!outputStream->open() || !inputStream->open()) { + tmpFile.remove(); + return 0; + } + char buffer[2048]; + std::size_t readed = 0; + do { + readed = inputStream->read(buffer, 2048); + outputStream->write(buffer, readed); + } while (readed > 0); + + LastUpdateTimeOption.setValue(ZLTime().inSeconds()); + return genericFile; +} + +NetworkLinkCollection::~NetworkLinkCollection() { +} + +static std::string normalize(const std::string &url) { + static const std::string PREFIX0 = "http://feedbooks.com/"; + static const std::string PREFIX1 = "http://www.feedbooks.com/"; + static const std::string STANZA_PREFIX = "http://feedbooks.com/book/stanza/"; + + std::string nURL = url; + if (ZLStringUtil::stringStartsWith(nURL, PREFIX1)) { + nURL = PREFIX0 + nURL.substr(PREFIX1.length()); + } + if (ZLStringUtil::stringStartsWith(nURL, STANZA_PREFIX)) { + nURL = PREFIX0 + "book/" + nURL.substr(STANZA_PREFIX.length()) + ".epub"; + } + return nURL; +} + +std::string NetworkLinkCollection::bookFileName(const BookReference &reference) { + myErrorMessage.clear(); + return bookFileName(::normalize(reference.cleanURL()), reference.BookFormat, reference.ReferenceType); +} + +static bool parseUrl(const std::string &url, std::string &hostAndPath, std::string &query) { + std::size_t hostBegin = url.find("://"); + if (hostBegin == std::string::npos) { + return false; + } + hostBegin += 3; + if (!url.compare(hostBegin, 4, "www.")) { + hostBegin += 4; + } + std::size_t pathEnd = url.find('?', hostBegin); + hostAndPath = url.substr(hostBegin, pathEnd - hostBegin); + if (pathEnd != std::string::npos) { + query = url.substr(pathEnd + 1); + } + return true; +} + +std::string NetworkLinkCollection::bookFileName(const std::string &url, BookReference::Format format, BookReference::Type type) { + static const std::string escapeChars = "<>:\"|?*\\"; + + std::string path; + std::string query; + if (!::parseUrl(url, path, query)) { + return std::string(); + } + + std::string fileName = DirectoryOption.value(); + if (!ZLStringUtil::stringEndsWith(fileName, ZLibrary::FileNameDelimiter)) { + fileName += ZLibrary::FileNameDelimiter; + } + if (type == BookReference::DOWNLOAD_DEMO) { + fileName += "Demos" + ZLibrary::FileNameDelimiter; + } + + for (std::size_t i = 0; i < path.size(); ++i) { + char ch = path[i]; + if (escapeChars.find(ch) != std::string::npos) { + path[i] = '_'; + } + if (ch == '/') { + path[i] = ZLibrary::FileNameDelimiter[0]; + } + } + + const std::size_t nameIndex = path.find_last_of(ZLibrary::FileNameDelimiter); + if (nameIndex + 1 == path.length()) { + path.resize(path.length() - 1); //removing ending / if exists + } + + std::string ext; + switch (format) { + case BookReference::EPUB: + ext = ".epub"; + break; + case BookReference::MOBIPOCKET: + ext = ".mobi"; + break; + case BookReference::FB2_ZIP: + ext = ".fb2.zip"; + break; + case BookReference::NONE: + break; + } + if (ext.empty()) { + std::size_t tmp = path.find('.', nameIndex); // using not find_last_of to preserve extensions like `.fb2.zip` + if (tmp == std::string::npos) { + return std::string(); + } + ext = path.substr(tmp); + path.resize(tmp); + } else if (ZLStringUtil::stringEndsWith(path, ext)) { + path.resize(path.size() - ext.size()); + } + + if (!query.empty()) { + std::size_t index = 0; + while (index < query.size()) { + std::size_t j = query.find('&', index); + if (j == std::string::npos) { + j = query.size(); + } + std::string param = query.substr(index, j); + if (!ZLStringUtil::stringStartsWith(param, "username=") + && !ZLStringUtil::stringStartsWith(param, "password=") + && !ZLStringUtil::stringEndsWith(param, "=")) { + std::size_t k = path.size(); + path.append("_").append(param); + while (k < path.size()) { + char ch = path[k]; + if (escapeChars.find(ch) != std::string::npos || ch == '/') { + path[k] = '_'; + } + ++k; + } + } + index = j + 1; + } + } + fileName.append(path); + fileName.append(ext); + return fileName; +} + + +bool NetworkLinkCollection::downloadBook(const BookReference &reference, std::string &fileName, shared_ptr<ZLNetworkRequest::Listener> listener) { + std::string nURL = ::normalize(reference.URL); + rewriteUrl(nURL); + const std::string nNetworkBookId = ::normalize(reference.cleanURL()); + const ZLResource &errorResource = ZLResource::resource("dialog")["networkError"]; + myErrorMessage.clear(); + + if (nURL.empty() || nNetworkBookId.empty()) { + myErrorMessage = errorResource["unknownErrorMessage"].value(); + return false; + } + fileName = bookFileName(nNetworkBookId, reference.BookFormat, reference.ReferenceType); + + //creating directory if not existed + const std::size_t directoryIndex = fileName.find_last_of(ZLibrary::FileNameDelimiter); + ZLFile(fileName.substr(0, directoryIndex)).directory(true); + + if (ZLFile(fileName).exists()) { + return true; + } + if (fileName.empty()) { + if (myErrorMessage.empty()) { + myErrorMessage = errorResource["unknownErrorMessage"].value(); + } + return false; + } + if (ZLFile(fileName).exists()) { + ZLFile(fileName).remove(); + } + ZLNetworkManager::Instance().downloadFile(nURL, fileName, listener); + return true; +} + +shared_ptr<NetworkBookCollection> NetworkLinkCollection::simpleSearch(const std::string &pattern) { + ZLNetworkRequest::Vector dataList; + std::vector<shared_ptr<NetworkOperationData> > opDataVector; + shared_ptr<NetworkBookCollection> result; + + myErrorMessage.clear(); + + for (std::vector<shared_ptr<NetworkLink> >::const_iterator it = myLinks.begin(); it != myLinks.end(); ++it) { + NetworkLink &link = **it; + if (link.isEnabled()) { + shared_ptr<NetworkOperationData> opData = new NetworkOperationData(link); + opDataVector.push_back(opData); + shared_ptr<ZLNetworkRequest> data = link.simpleSearchData(*opData, pattern); + if (!data.isNull()) { + dataList.push_back(data); + } + } + } + + while (myErrorMessage.empty() && !dataList.empty()) { + myErrorMessage = ZLNetworkManager::Instance().perform(dataList); + + for (std::vector<shared_ptr<NetworkOperationData> >::const_iterator jt = opDataVector.begin(); jt != opDataVector.end(); ++jt) { + NetworkOperationData &opData = **jt; + if (!opData.Items.empty() && result.isNull()) { + result = new NetworkBookCollection(); + } + for (NetworkItem::List::const_iterator kt = opData.Items.begin(); kt != opData.Items.end(); ++kt) { + result->addBook(*kt); + } + } + + dataList.clear(); + + for (std::vector<shared_ptr<NetworkOperationData> >::const_iterator jt = opDataVector.begin(); jt != opDataVector.end(); ++jt) { + shared_ptr<ZLNetworkRequest> data = (*jt)->resume(); + if (!data.isNull()) { + dataList.push_back(data); + } + } + } + + return result; +} + +shared_ptr<NetworkBookCollection> NetworkLinkCollection::advancedSearch(const std::string &titleAndSeries, const std::string &author, const std::string &tag, const std::string &annotation) { + ZLNetworkRequest::Vector dataList; + std::vector<shared_ptr<NetworkOperationData> > opDataVector; + shared_ptr<NetworkBookCollection> result; + + myErrorMessage.clear(); + + for (std::vector<shared_ptr<NetworkLink> >::const_iterator it = myLinks.begin(); it != myLinks.end(); ++it) { + NetworkLink &link = **it; + if (link.isEnabled()) { + shared_ptr<NetworkOperationData> opData = new NetworkOperationData(link); + opDataVector.push_back(opData); + shared_ptr<ZLNetworkRequest> data = link.advancedSearchData(*opData, titleAndSeries, author, tag, annotation); + if (!data.isNull()) { + dataList.push_back(data); + } + } + } + + while (myErrorMessage.empty() && !dataList.empty()) { + myErrorMessage = ZLNetworkManager::Instance().perform(dataList); + + for (std::vector<shared_ptr<NetworkOperationData> >::const_iterator jt = opDataVector.begin(); jt != opDataVector.end(); ++jt) { + NetworkOperationData &opData = **jt; + if (!opData.Items.empty() && result.isNull()) { + result = new NetworkBookCollection(); + } + for (NetworkItem::List::const_iterator kt = opData.Items.begin(); kt != opData.Items.end(); ++kt) { + result->addBook(*kt); + } + } + + dataList.clear(); + + for (std::vector<shared_ptr<NetworkOperationData> >::const_iterator jt = opDataVector.begin(); jt != opDataVector.end(); ++jt) { + shared_ptr<ZLNetworkRequest> data = (*jt)->resume(); + if (!data.isNull()) { + dataList.push_back(data); + } + } + } + + return result; +} + +NetworkLinkCollection::LinkVector NetworkLinkCollection::activeLinks() const { + LinkVector filteredList; + for (std::size_t i = 0; i < myLinks.size(); ++i) { + shared_ptr<NetworkLink> link = myLinks.at(i); + if (link->isEnabled()) { + filteredList.push_back(link); + } + } + return filteredList; +} + +std::size_t NetworkLinkCollection::size() const { + return myLinks.size(); +} + +NetworkLink &NetworkLinkCollection::link(std::size_t index) const { + return *myLinks[index]; +} + +std::size_t NetworkLinkCollection::numberOfEnabledLinks() const { + std::size_t count = 0; + for (std::vector<shared_ptr<NetworkLink> >::const_iterator it = myLinks.begin(); it != myLinks.end(); ++it) { + if ((*it)->isEnabled()) { + ++count; + } + } + return count; +} + +void NetworkLinkCollection::rewriteUrl(std::string &url, bool externalUrl) const { + const std::string host = + ZLUnicodeUtil::toLower(ZLNetworkUtil::hostFromUrl(url)); + for (std::vector<shared_ptr<NetworkLink> >::const_iterator it = myLinks.begin(); it != myLinks.end(); ++it) { + if (host.find((*it)->getSiteName()) != std::string::npos) { + (*it)->rewriteUrl(url, externalUrl); + } + } +} diff --git a/fbreader/src/network/NetworkLinkCollection.h b/fbreader/src/network/NetworkLinkCollection.h new file mode 100644 index 0000000..080959d --- /dev/null +++ b/fbreader/src/network/NetworkLinkCollection.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __NETWORKLINKCOLLECTION_H__ +#define __NETWORKLINKCOLLECTION_H__ + +#include <string> +#include <vector> + +#include <shared_ptr.h> + +#include <ZLOptions.h> +#include <ZLNetworkRequest.h> + +#include "NetworkItems.h" + +class NetworkLink; +class NetworkBookCollection; +class BookReference; + +class NetworkLinkCollection { + +public: + typedef std::vector<shared_ptr<NetworkLink> > LinkVector; + +private: + class Comparator; + +public: + static NetworkLinkCollection &Instance(); + +private: + static NetworkLinkCollection *ourInstance; + +public: + ZLStringOption DirectoryOption; + ZLIntegerOption LastUpdateTimeOption; + +private: + NetworkLinkCollection(); + ~NetworkLinkCollection(); + +public: + void initialize(); + + std::string bookFileName(const BookReference &reference); + + bool downloadBook(const BookReference &reference, std::string &fileName, shared_ptr<ZLNetworkRequest::Listener> listener); + + shared_ptr<NetworkBookCollection> simpleSearch(const std::string &pattern); + shared_ptr<NetworkBookCollection> advancedSearch(const std::string &titleAndSeries, const std::string &author, const std::string &tag, const std::string &annotation); + + LinkVector activeLinks() const; + std::size_t size() const; + std::size_t numberOfEnabledLinks() const; + NetworkLink &link(std::size_t index) const; + + const std::string &errorMessage() const; + + void rewriteUrl(std::string &url, bool externalUrl = false) const; + + //void deleteLink(NetworkLink& link); + //void saveLink(NetworkLink& link, bool isAuto = false); + +private: + void synchronize(); + + std::string bookFileName(const std::string &url, BookReference::Format format, BookReference::Type type); + + void updateLinks(std::string genericUrl); + shared_ptr<ZLFile> getGenericFile(std::string genericUrl); + void addOrUpdateLink(shared_ptr<NetworkLink> link); + +private: + LinkVector myLinks; + std::string myErrorMessage; + bool myIsInitialized; + +friend class NetworkLinksUpdater; +friend class NetworkLinkCollectionSynchronizer; +}; + +inline const std::string &NetworkLinkCollection::errorMessage() const { return myErrorMessage; } + +#endif /* __NETWORKLINKCOLLECTION_H__ */ diff --git a/fbreader/src/network/NetworkOperationData.cpp b/fbreader/src/network/NetworkOperationData.cpp new file mode 100644 index 0000000..6988071 --- /dev/null +++ b/fbreader/src/network/NetworkOperationData.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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 <ZLNetworkRequest.h> + +#include "NetworkLink.h" +#include "NetworkOperationData.h" + +NetworkOperationData::NetworkOperationData(const NetworkLink &link) : Link(link) { +} + +void NetworkOperationData::clear() { + Items.clear(); + ResumeURI.clear(); +} + +shared_ptr<ZLNetworkRequest> NetworkOperationData::resume() { + shared_ptr<ZLNetworkRequest> request = Link.resume(*this); + clear(); + return request; +} diff --git a/fbreader/src/network/NetworkOperationData.h b/fbreader/src/network/NetworkOperationData.h new file mode 100644 index 0000000..4d4a46f --- /dev/null +++ b/fbreader/src/network/NetworkOperationData.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __NETWORKOPERATIONDATA_H__ +#define __NETWORKOPERATIONDATA_H__ + +#include <shared_ptr.h> + +#include "NetworkItems.h" + +class ZLNetworkRequest; + +class NetworkLink; + +class NetworkOperationData { + +public: + NetworkOperationData(const NetworkLink &link); + + void clear(); + shared_ptr<ZLNetworkRequest> resume(); + +public: + const NetworkLink &Link; + NetworkItem::List Items; + std::string ResumeURI; +}; + +#endif /* __NETWORKOPERATIONDATA_H__ */ diff --git a/fbreader/src/network/SearchResult.cpp b/fbreader/src/network/SearchResult.cpp new file mode 100644 index 0000000..2b66326 --- /dev/null +++ b/fbreader/src/network/SearchResult.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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 "SearchResult.h" + +SearchResult SearchResult::ourLastSearchResult; + + +SearchResult::SearchResult() { +} + +const SearchResult &SearchResult::lastSearchResult() { + return ourLastSearchResult; +} + +void SearchResult::setLastSearchResult(const std::string &summary, shared_ptr<NetworkBookCollection> bookCollection) { + ourLastSearchResult.mySummary = summary; + ourLastSearchResult.myBookCollection = bookCollection; +} + diff --git a/fbreader/src/network/SearchResult.h b/fbreader/src/network/SearchResult.h new file mode 100644 index 0000000..bd18b71 --- /dev/null +++ b/fbreader/src/network/SearchResult.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __SEARCHRESULT_H__ +#define __SEARCHRESULT_H__ + +#include "NetworkBookCollection.h" + +class SearchResult { + +private: + static SearchResult ourLastSearchResult; + +private: + SearchResult(); + +public: + static const SearchResult &lastSearchResult(); + static void setLastSearchResult(const std::string &summary, shared_ptr<NetworkBookCollection> bookCollection); + +public: + const std::string &summary() const; + shared_ptr<NetworkBookCollection> collection() const; + +private: + std::string mySummary; + shared_ptr<NetworkBookCollection> myBookCollection; +}; + +inline const std::string &SearchResult::summary() const { return mySummary; } +inline shared_ptr<NetworkBookCollection> SearchResult::collection() const { return myBookCollection; } + +#endif /* __SEARCHRESULT_H__ */ diff --git a/fbreader/src/network/UserList.cpp b/fbreader/src/network/UserList.cpp new file mode 100644 index 0000000..1712788 --- /dev/null +++ b/fbreader/src/network/UserList.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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 <algorithm> + +#include <ZLOptions.h> +#include <ZLStringUtil.h> + +#include "UserList.h" + + +static const unsigned int MAX_USER_NAMES = 10; + +static const std::string USER_LIST = "userList-"; +static const std::string USER = "user"; + +UserList::UserList(const std::string &siteName) : myGroupName(USER_LIST + siteName) { + for (unsigned int i = 0; i < MAX_USER_NAMES; ++i) { + std::string userOptionName(USER); + ZLStringUtil::appendNumber(userOptionName, i); + std::string userName = ZLStringOption(ZLCategoryKey::NETWORK, myGroupName, userOptionName, "").value(); + if (!userName.empty()) { + myUserNames.push_back(userName); + mySavedNames.insert(userName); + } + } + if (myUserNames.empty()) { + myUserNames.push_back(std::string()); + } +} + +UserList::~UserList() { + unsigned int i = 0; + for (std::size_t k = 0; k < myUserNames.size() && i < MAX_USER_NAMES; ++k) { + const std::string &name = myUserNames[k]; + if (mySavedNames.find(name) != mySavedNames.end()) { + std::string userOptionName(USER); + ZLStringUtil::appendNumber(userOptionName, i++); + ZLStringOption userOption(ZLCategoryKey::NETWORK, myGroupName, userOptionName, ""); + userOption.setValue(name); + } + } + while (i < MAX_USER_NAMES) { + std::string userOptionName(USER); + ZLStringUtil::appendNumber(userOptionName, i++); + ZLStringOption userOption(ZLCategoryKey::NETWORK, myGroupName, userOptionName, ""); + userOption.setValue(""); + } +} + +const std::vector<std::string> &UserList::users() const { + return myUserNames; +} + +void UserList::addUser(const std::string &user) { + std::vector<std::string>::iterator it; + while ((it = std::find(myUserNames.begin(), myUserNames.end(), user)) != myUserNames.end()) { + myUserNames.erase(it); + } + myUserNames.insert(myUserNames.begin(), user); +} + +void UserList::saveUser(const std::string &user) { + std::vector<std::string>::iterator it = std::find(myUserNames.begin(), myUserNames.end(), user); + if (it == myUserNames.end()) { + myUserNames.insert(myUserNames.begin(), user); + } + mySavedNames.insert(user); +} diff --git a/fbreader/src/network/UserList.h b/fbreader/src/network/UserList.h new file mode 100644 index 0000000..d1f298f --- /dev/null +++ b/fbreader/src/network/UserList.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __USERLIST_H__ +#define __USERLIST_H__ + +#include <string> +#include <vector> +#include <set> + + +class UserList { + +public: + UserList(const std::string &siteName); + ~UserList(); + + const std::vector<std::string> &users() const; + void addUser(const std::string &user); + void saveUser(const std::string &user); + +private: + std::string myGroupName; + std::vector<std::string> myUserNames; + std::set<std::string> mySavedNames; +}; + +#endif /* __USERLIST_H__ */ diff --git a/fbreader/src/network/atom/ATOMConstructs.cpp b/fbreader/src/network/atom/ATOMConstructs.cpp new file mode 100644 index 0000000..9684825 --- /dev/null +++ b/fbreader/src/network/atom/ATOMConstructs.cpp @@ -0,0 +1,339 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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 "ATOMConstructs.h" + +#include <ZLStringUtil.h> + +#include <math.h> + + + +const std::string ATOMCommonAttributes::XML_BASE = "xml:base"; +const std::string ATOMCommonAttributes::XML_LANG = "xml:lang"; + + +ATOMCommonAttributes::ATOMCommonAttributes() { +} + +ATOMCommonAttributes::~ATOMCommonAttributes() { +} + +void ATOMCommonAttributes::readAttributes(const std::map<std::string, std::string> &attributes) { + readAttribute(XML_BASE, attributes); + readAttribute(XML_LANG, attributes); +} + +void ATOMCommonAttributes::readAttribute(const std::string &name, const std::map<std::string, std::string> &attributes) { + std::map<std::string, std::string>::const_iterator it = attributes.find(name); + if (it != attributes.end()) { + myAttributes[name] = it->second; + } +} + +void ATOMCommonAttributes::setUserData(const std::string &key, const std::string &value) { + myUserData[key] = value; +} + +const std::string ATOMCommonAttributes::userData(const std::string &key) const { + std::map<std::string,std::string>::const_iterator it = myUserData.find(key); + return (it != myUserData.end()) ? it->second : std::string(); +} + +ATOMPersonConstruct::ATOMPersonConstruct() { +} + +ATOMPersonConstruct::ATOMPersonConstruct(const std::string &name) : myName(name) { +} + + +ATOMDateConstruct::ATOMDateConstruct(int year) : + myYear(year), myMonth(0), myDay(0), + myHour(0), myMinutes(0), mySeconds(0), mySecondFraction(0), myTZHour(0), myTZMinutes(0) { +} + +ATOMDateConstruct::ATOMDateConstruct(int year, int month, int day) : + myYear(year), myMonth(month), myDay(day), + myHour(0), myMinutes(0), mySeconds(0), mySecondFraction(0), myTZHour(0), myTZMinutes(0) { +} + +ATOMDateConstruct::ATOMDateConstruct(int year, int month, int day, int hour, int minutes, int seconds) : + myYear(year), myMonth(month), myDay(day), + myHour(hour), myMinutes(minutes), mySeconds(seconds), mySecondFraction(0), myTZHour(0), myTZMinutes(0) { +} + +ATOMDateConstruct::ATOMDateConstruct(int year, int month, int day, int hour, int minutes, int seconds, float sfract) : + myYear(year), myMonth(month), myDay(day), + myHour(hour), myMinutes(minutes), mySeconds(seconds), mySecondFraction(sfract), myTZHour(0), myTZMinutes(0) { +} + +ATOMDateConstruct::ATOMDateConstruct(int year, int month, int day, int hour, int minutes, int seconds, float sfract, int tzhour, int tzminutes) : + myYear(year), myMonth(month), myDay(day), + myHour(hour), myMinutes(minutes), mySeconds(seconds), mySecondFraction(sfract), myTZHour(tzhour), myTZMinutes(tzminutes) { +} + +bool ATOMDateConstruct::operator<(const ATOMDateConstruct &a) const { + if (myYear < a.myYear) return true; + if (myYear > a.myYear) return false; + + if (myMonth < a.myMonth) return true; + if (myMonth > a.myMonth) return false; + + if (myDay < a.myDay) return true; + if (myDay > a.myDay) return false; + + if (myHour < a.myHour) return true; + if (myHour > a.myHour) return false; + + if (myMinutes < a.myMinutes) return true; + if (myMinutes > a.myMinutes) return false; + + if (mySeconds < a.mySeconds) return true; + if (mySeconds > a.mySeconds) return false; + +// if (mySecondFraction < a.mySecondFraction) return true; +// if (mySecondFraction > a.mySecondFraction) return false; + return false; +} + +bool ATOMDateConstruct::operator>(const ATOMDateConstruct &a) const { + if (myYear > a.myYear) return true; + if (myYear < a.myYear) return false; + + if (myMonth > a.myMonth) return true; + if (myMonth < a.myMonth) return false; + + if (myDay > a.myDay) return true; + if (myDay < a.myDay) return false; + + if (myHour > a.myHour) return true; + if (myHour < a.myHour) return false; + + if (myMinutes > a.myMinutes) return true; + if (myMinutes < a.myMinutes) return false; + + if (mySeconds > a.mySeconds) return true; + if (mySeconds < a.mySeconds) return false; + +// if (mySecondFraction < a.mySecondFraction) return true; +// if (mySecondFraction > a.mySecondFraction) return false; + return false; +} + +void ATOMDateConstruct::makeStringLength(std::string &str, int len) { + const int lendiff = str.length() - len; + if (lendiff > 0) { + str = str.substr(lendiff); + } else { + str = std::string(-lendiff, '0') + str; + } +} + + +std::string ATOMDateConstruct::getDateTime(bool brief) const { + std::string timezone = "Z"; + if (myTZMinutes != 0 || myTZHour != 0) { + int tzminnum = myTZMinutes; + int tzhournum = myTZHour; + char sign; + if (tzhournum == 0) { + sign = (tzminnum >= 0) ? '+' : '-'; + } else { + sign = (tzhournum > 0) ? '+' : '-'; + if (tzhournum > 0 && tzminnum < 0) { + --tzhournum; + tzminnum = 60 + tzminnum; + } else if (tzhournum < 0 && tzminnum > 0) { + ++tzhournum; + tzminnum = 60 - tzminnum; + } + } + std::string tzmin, tzhour; + ZLStringUtil::appendNumber(tzmin, tzminnum < 0 ? -tzminnum : tzminnum); + ZLStringUtil::appendNumber(tzhour, tzhournum < 0 ? -tzhournum : tzhournum); + makeStringLength(tzmin, 2); + makeStringLength(tzhour, 2); + timezone = sign + tzhour + ":" + tzmin; + } + + std::string time; + if (mySecondFraction >= 0.01) { + std::string sfr; + unsigned int sfrnum = (unsigned int) floor(100 * mySecondFraction + 0.5); + ZLStringUtil::appendNumber(sfr, sfrnum); + makeStringLength(sfr, 2); + time = "." + sfr; + } + if (!brief || !time.empty() || mySeconds != 0) { + std::string sec; + ZLStringUtil::appendNumber(sec, mySeconds); + makeStringLength(sec, 2); + time = ":" + sec + time; + } + if (!brief || !time.empty() || myHour != 0 || myMinutes != 0 || timezone != "Z") { + std::string hour, min; + ZLStringUtil::appendNumber(hour, myHour); + ZLStringUtil::appendNumber(min, myMinutes); + makeStringLength(hour, 2); + makeStringLength(min, 2); + time = hour + ":" + min + time; + } + + std::string date; + if (!brief || !time.empty() || myDay != 0) { + std::string day; + ZLStringUtil::appendNumber(day, myDay); + makeStringLength(day, 2); + date = "-" + day; + } + if (!brief || !date.empty() || myMonth != 0) { + std::string month; + ZLStringUtil::appendNumber(month, myMonth); + makeStringLength(month, 2); + date = "-" + month + date; + } + + std::string year; + ZLStringUtil::appendNumber(year, myYear); + makeStringLength(year, 4); + date = year + date; + + if (!brief || !time.empty()) { + date = date + "T" + time + timezone; + } + return date; +} + +bool ATOMDateConstruct::parse(const std::string &str, ATOMDateConstruct &dateTime) { + dateTime.setYear(0); + dateTime.setMonth(0); + dateTime.setDay(0); + dateTime.setHour(0); + dateTime.setMinutes(0); + dateTime.setSeconds(0); + dateTime.setSecondFraction(0); + dateTime.setTZHour(0); + dateTime.setTZMinutes(0); + const int len = str.length(); + if (len != 4 && len != 7 && len != 10 && len != 17 && len != 20 && len < 22) { + return false; + } + int num = 0, sign = 1; + float fnum = 0.0, fmult = 0.1; + int start, end, log; + char ch; + end = 4; start = 0; log = 0; + while (start < len) { + ch = str[start++]; + if (!std::isdigit(ch)) { + return false; + } + num = 10 * num + ((int) (ch - '0')); + fnum += fmult * ((int) (ch - '0')); + fmult *= 0.1; + if (start == end) { + switch (log) { + case 0: dateTime.setYear(num); break; + case 1: dateTime.setMonth(num); break; + case 2: dateTime.setDay(num); break; + case 3: dateTime.setHour(num); break; + case 4: dateTime.setMinutes(num); break; + case 5: dateTime.setSeconds(num); break; + case 6: dateTime.setSecondFraction(fnum); break; + case 7: dateTime.setTZHour(sign * num); break; + case 8: dateTime.setTZMinutes(sign * num); break; + default: return false; + } + num = 0; fnum = 0.0; fmult = 0.1; + if (start == len) return true; + switch (log) { + case 0: + case 1: + if (str[start++] != '-') return false; + end = start + 2; + break; + case 2: + if (str[start++] != 'T') return false; + end = start + 2; + break; + case 3: + case 7: + if (str[start++] != ':') return false; + end = start + 2; + break; + case 4: + ch = str[start++]; + if (ch == ':') { + end = start + 2; + } else if (ch == '+' || ch == '-') { + sign = (ch == '-') ? -1 : 1; + log += 2; + end = start + 2; + } else if (ch == 'Z') { + return true; + } else return false; + break; + case 5: + ch = str[start++]; + if (ch == '.') { + end = start; + while (std::isdigit(str[++end])) /* NOP */; + } else if (ch == '+' || ch == '-') { + sign = (ch == '-') ? -1 : 1; + log += 1; + end = start + 2; + } else if (ch == 'Z') { + return true; + } else return false; + break; + case 6: + ch = str[start++]; + if (ch == '+' || ch == '-') { + sign = (ch == '-') ? -1 : 1; + end = start + 2; + } else if (ch == 'Z') { + return true; + } else return false; + break; + //case 8: + default: return false; + } + ++log; + } + } + return false; +} + +long ATOMDateConstruct::getLongSeconds_stupid() { + return ((((((myYear - 2000) * 12 + myMonth) * 31 + myDay) * 24 + myHour) * 60 + myMinutes) * 60 + mySeconds); +} + +void ATOMDateConstruct::setLongSeconds_stupid(long t) { + myYear = t / (12*31*24*60*60) + 2000; + t = t % (12*31*24*60*60); + myMonth = t / (31*24*60*60); + t = t % (31*24*60*60); + myDay = t / (24*60*60); + t = t % (24*60*60); + myHour = t / (60*60); + t = t % (60*60); + myMinutes = t / (60); + t = t % (60); + mySeconds = t; +} diff --git a/fbreader/src/network/atom/ATOMConstructs.h b/fbreader/src/network/atom/ATOMConstructs.h new file mode 100644 index 0000000..2497bd4 --- /dev/null +++ b/fbreader/src/network/atom/ATOMConstructs.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __ATOMCONSTRUCTS_H__ +#define __ATOMCONSTRUCTS_H__ + +#include <map> +#include <string> + + +class ATOMCommonAttributes { + +public: + static const std::string XML_BASE; + static const std::string XML_LANG; + +public: + ATOMCommonAttributes(); + virtual ~ATOMCommonAttributes(); + +public: + std::map<std::string, std::string> &attributes() { return myAttributes; } + const std::map<std::string, std::string> &attributes() const { return myAttributes; } + + std::string &base() { return myAttributes[XML_BASE]; } + std::string &lang() { return myAttributes[XML_LANG]; } + + virtual void readAttributes(const std::map<std::string, std::string> &attributes); + + void setUserData(const std::string &key, const std::string &value); + const std::string userData(const std::string &key) const; + +protected: + void readAttribute(const std::string &name, const std::map<std::string, std::string> &attributes); + +private: + std::map<std::string, std::string> myAttributes; + std::map<std::string,std::string> myUserData; +}; + + +class ATOMPersonConstruct : public ATOMCommonAttributes { + +public: + ATOMPersonConstruct(); + ATOMPersonConstruct(const std::string &name); + + const std::string &name() const { return myName; } + const std::string &uri() const { return myUri; } + const std::string &email() const { return myEmail; } + + void setName(const std::string &name) { myName = name; } + void setUri(const std::string &uri) { myUri = uri; } + void setEmail(const std::string &email) { myEmail = email; } + +private: + std::string myName; + std::string myUri; + std::string myEmail; +}; + + +class ATOMDateConstruct : public ATOMCommonAttributes { + +public: + static bool parse(const std::string &str, ATOMDateConstruct &dateTime); + +public: + ATOMDateConstruct(int year); + ATOMDateConstruct(int year, int month, int day); + ATOMDateConstruct(int year, int month, int day, int hour, int minutes, int seconds); + ATOMDateConstruct(int year, int month, int day, int hour, int minutes, int seconds, float sfract); + ATOMDateConstruct(int year, int month, int day, int hour, int minutes, int seconds, float sfract, int tzhour, int tzminutes); + + bool operator <(const ATOMDateConstruct& a) const; + bool operator >(const ATOMDateConstruct& a) const; + + std::string getDateTime(bool brief = false) const; + + int year() const { return myYear; } + int month() const { return myMonth; } + int day() const { return myDay; } + int hour() const { return myHour; } + int minutes() const { return myMinutes; } + int seconds() const { return mySeconds; } + float secondFraction() const { return mySecondFraction; } + int timeZoneHour() const { return myTZHour; } + int timeZoneMinutes() const { return myTZMinutes; } + + void setYear(int year) { myYear = year; } + void setMonth(int month) { myMonth = month; } + void setDay(int day) { myDay = day; } + void setHour(int hour) { myHour = hour; } + void setMinutes(int minutes) { myMinutes = minutes; } + void setSeconds(int seconds) { mySeconds = seconds; } + void setSecondFraction(float sfract) { mySecondFraction = sfract; } + void setTZHour(int tzhour) { myTZHour = tzhour; } + void setTZMinutes(int tzminutes) { myTZMinutes = tzminutes; } + + long getLongSeconds_stupid(); + void setLongSeconds_stupid(long t); + +private: + static void makeStringLength(std::string &str, int len); + +private: + int myYear; + int myMonth; + int myDay; + int myHour; + int myMinutes; + int mySeconds; + float mySecondFraction; + int myTZHour; + int myTZMinutes; +}; + + +#endif /* __ATOMCONSTRUCTS_H__ */ diff --git a/fbreader/src/network/atom/ATOMContainers.cpp b/fbreader/src/network/atom/ATOMContainers.cpp new file mode 100644 index 0000000..fb05c10 --- /dev/null +++ b/fbreader/src/network/atom/ATOMContainers.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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 "ATOMContainers.h" + +ATOMEntry::ATOMEntry() { +} + +ATOMEntry::ATOMEntry(shared_ptr<ATOMId> id, const std::string &title, shared_ptr<ATOMUpdated> updated) : + myId(id), myTitle(title), myUpdated(updated) { +} + + + +ATOMFeedMetadata::ATOMFeedMetadata() { +} + +ATOMFeedMetadata::ATOMFeedMetadata(shared_ptr<ATOMId> id, const std::string &title, shared_ptr<ATOMUpdated> updated) : + myId(id), myTitle(title), myUpdated(updated) { +} + + + +/* +ATOMFeed::ATOMFeed() { +} + +ATOMFeed::ATOMFeed(const ATOMId &id, const std::string &title, shared_ptr<ATOMUpdated> updated) : + ATOMFeedMatadata(id, title, updated) { +} +*/ + + diff --git a/fbreader/src/network/atom/ATOMContainers.h b/fbreader/src/network/atom/ATOMContainers.h new file mode 100644 index 0000000..1fb3f92 --- /dev/null +++ b/fbreader/src/network/atom/ATOMContainers.h @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __ATOMCONTAINTERS_H__ +#define __ATOMCONTAINTERS_H__ + +#include <vector> + +#include <shared_ptr.h> + +#include "ATOMMetadata.h" + + + +class ATOMEntry : public ATOMCommonAttributes { + +public: + ATOMEntry(); + ATOMEntry(shared_ptr<ATOMId> id, const std::string &title, shared_ptr<ATOMUpdated> updated); + + std::vector<shared_ptr<ATOMAuthor> > &authors() { return myAuthors; } + std::vector<shared_ptr<ATOMCategory> > &categories() { return myCategories; } + std::vector<shared_ptr<ATOMContributor> > &contributors() { return myContributors; } + std::vector<shared_ptr<ATOMLink> > &links() { return myLinks; } + + shared_ptr<ATOMPublished> published() { return myPublished; } + shared_ptr<ATOMIcon> icon() { return myIcon; } + const std::string &rights() { return myRights; } + const std::string &summary() { return mySummary; } + const std::string &title() { return myTitle; } + shared_ptr<ATOMUpdated> updated() { return myUpdated; } + + void setPublished(shared_ptr<ATOMPublished> published) { myPublished = published; } + void setIcon(shared_ptr<ATOMIcon> icon) { myIcon = icon; } + void setRights(const std::string &rights) { myRights = rights; } + void setSummary(const std::string &summary) { mySummary = summary; } + void setTitle(const std::string &title) { myTitle = title; } + void setUpdated(shared_ptr<ATOMUpdated> updated) { myUpdated = updated; } + + shared_ptr<ATOMId> id() { return myId; } + void setId(shared_ptr<ATOMId> id) { myId = id; } + +private: + shared_ptr<ATOMId> myId; + + std::vector<shared_ptr<ATOMAuthor> > myAuthors; + std::vector<shared_ptr<ATOMCategory> > myCategories; + //shared_ptr<ATOMContent> myContent; TODO: implement ATOMContent + std::vector<shared_ptr<ATOMContributor> > myContributors; + std::vector<shared_ptr<ATOMLink> > myLinks; + shared_ptr<ATOMIcon> myIcon; + shared_ptr<ATOMPublished> myPublished; + std::string myRights; // TODO: implement ATOMTextConstruct + //shared_ptr<ATOMSource> mySource; // TODO: implement ATOMSource + std::string mySummary; // TODO: implement ATOMTextConstruct + std::string myTitle; // TODO: implement ATOMTextConstruct + shared_ptr<ATOMUpdated> myUpdated; +}; + + +class ATOMFeedMetadata : public ATOMCommonAttributes { + +public: + ATOMFeedMetadata(); + ATOMFeedMetadata(shared_ptr<ATOMId> id, const std::string &title, shared_ptr<ATOMUpdated> updated); + + std::vector<shared_ptr<ATOMAuthor> > &authors() { return myAuthors; } + std::vector<shared_ptr<ATOMCategory> > &categories() { return myCategories; } + std::vector<shared_ptr<ATOMContributor> > &contributors() { return myContributors; } + std::vector<shared_ptr<ATOMLink> > &links() { return myLinks; } + + shared_ptr<ATOMGenerator> generator() { return myGenerator; } + shared_ptr<ATOMIcon> icon() { return myIcon; } + shared_ptr<ATOMLogo> logo() { return myLogo; } + const std::string &rights() { return myRights; } + const std::string &subtitle() { return mySubtitle; } + const std::string &summary() { return mySummary; } + const std::string &title() { return myTitle; } + shared_ptr<ATOMUpdated> updated() { return myUpdated; } + + void setGenerator(shared_ptr<ATOMGenerator> generator) { myGenerator = generator; } + void setIcon(shared_ptr<ATOMIcon> icon) { myIcon = icon; } + void setLogo(shared_ptr<ATOMLogo> logo) { myLogo = logo; } + void setRights(const std::string &rights) { myRights = rights; } + void setSubtitle(const std::string &subtitle) { mySubtitle = subtitle; } + void setSummary(const std::string &summary) { mySummary = summary; } + void setTitle(const std::string &title) { myTitle = title; } + void setUpdated(shared_ptr<ATOMUpdated> updated) { myUpdated = updated; } + + shared_ptr<ATOMId> id() { return myId; } + void setId(shared_ptr<ATOMId> id) { myId = id; } + +private: + shared_ptr<ATOMId> myId; + + std::vector<shared_ptr<ATOMAuthor> > myAuthors; + std::vector<shared_ptr<ATOMCategory> > myCategories; + std::vector<shared_ptr<ATOMContributor> > myContributors; + shared_ptr<ATOMGenerator> myGenerator; + shared_ptr<ATOMIcon> myIcon; + std::vector<shared_ptr<ATOMLink> > myLinks; + shared_ptr<ATOMLogo> myLogo; + std::string myRights; // TODO: implement ATOMTextConstruct + std::string mySubtitle; // TODO: implement ATOMTextConstruct + std::string mySummary; // TODO: implement ATOMTextConstruct + std::string myTitle; // TODO: implement ATOMTextConstruct + shared_ptr<ATOMUpdated> myUpdated; +}; + + +/* +class ATOMFeed : public ATOMFeedMetadata { + +public: + ATOMFeed(); + ATOMFeed(const ATOMId &id, const std::string &title, shared_ptr<ATOMUpdated> updated); + + std::vector<shared_ptr<ATOMEntry> > entries() { return myEntries; } + +private: + std::vector<shared_ptr<ATOMEntry> > myEntries; +}; +*/ + + +#endif /* __ATOMCONTAINTERS_H__ */ diff --git a/fbreader/src/network/atom/ATOMMetadata.cpp b/fbreader/src/network/atom/ATOMMetadata.cpp new file mode 100644 index 0000000..cb81e0e --- /dev/null +++ b/fbreader/src/network/atom/ATOMMetadata.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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 "ATOMMetadata.h" + + +const std::string ATOMConstants::TYPE_TEXT = "text"; +const std::string ATOMConstants::TYPE_HTML = "html"; +const std::string ATOMConstants::TYPE_XHTML = "xhtml"; + +const std::string ATOMConstants::TYPE_DEFAULT = TYPE_TEXT; + +const std::string ATOMConstants::REL_ALTERNATE = "alternate"; +const std::string ATOMConstants::REL_RELATED = "related"; +const std::string ATOMConstants::REL_SELF = "self"; +const std::string ATOMConstants::REL_ENCLOSURE = "enclosure"; +const std::string ATOMConstants::REL_VIA = "via"; + + + +const std::string ATOMCategory::TERM = "term"; +const std::string ATOMCategory::SCHEME = "scheme"; +const std::string ATOMCategory::LABEL = "label"; + +const std::string ATOMGenerator::URI = "uri"; +const std::string ATOMGenerator::VERSION_ATT = "version"; + +const std::string ATOMLink::HREF = "href"; +const std::string ATOMLink::REL = "rel"; +const std::string ATOMLink::TYPE = "type"; +const std::string ATOMLink::HREFLANG = "hreflang"; +const std::string ATOMLink::TITLE = "title"; +const std::string ATOMLink::LENGTH = "length"; + + + +ATOMAuthor::ATOMAuthor() { +} + +ATOMAuthor::ATOMAuthor(const std::string &name) : ATOMPersonConstruct(name) { +} + + + +ATOMCategory::ATOMCategory() { +} + +ATOMCategory::ATOMCategory(const std::string &termStr) { + term() = termStr; +} + +void ATOMCategory::readAttributes(const std::map<std::string, std::string> &attributes) { + ATOMCommonAttributes::readAttributes(attributes); + readAttribute(TERM, attributes); + readAttribute(SCHEME, attributes); + readAttribute(LABEL, attributes); +} + + + +ATOMContributor::ATOMContributor() { +} + +ATOMContributor::ATOMContributor(const std::string &name) : ATOMPersonConstruct(name) { +} + + + +ATOMGenerator::ATOMGenerator() { +} + +ATOMGenerator::ATOMGenerator(const std::string &text) : myText(text) { +} + +void ATOMGenerator::readAttributes(const std::map<std::string, std::string> &attributes) { + ATOMCommonAttributes::readAttributes(attributes); + readAttribute(URI, attributes); + readAttribute(VERSION_ATT, attributes); +} + + + +ATOMIcon::ATOMIcon() { +} + +ATOMIcon::ATOMIcon(const std::string &uri) : myUri(uri) { +} + + + +ATOMId::ATOMId() { +} + +ATOMId::ATOMId(const std::string &uri) : myUri(uri) { +} + + + +ATOMLink::ATOMLink() { +} + +ATOMLink::ATOMLink(const std::string &hrefStr) { + href() = hrefStr; +} + +ATOMLink::ATOMLink(const std::string &hrefStr, const std::string &relStr) { + href() = hrefStr; + rel() = relStr; +} + +ATOMLink::ATOMLink(const std::string &hrefStr, const std::string &relStr, const std::string &typeStr){ + href() = hrefStr; + rel() = relStr; + type() = typeStr; +} + +ATOMLink::ATOMLink(const std::string &hrefStr, const std::string &relStr, const std::string &typeStr, const std::string &titleStr) { + href() = hrefStr; + rel() = relStr; + type() = typeStr; + title() = titleStr; +} + +void ATOMLink::readAttributes(const std::map<std::string, std::string> &attributes) { + ATOMCommonAttributes::readAttributes(attributes); + readAttribute(HREF, attributes); + readAttribute(REL, attributes); + readAttribute(TYPE, attributes); + readAttribute(HREFLANG, attributes); + readAttribute(TITLE, attributes); + readAttribute(LENGTH, attributes); +} + +ATOMLogo::ATOMLogo() { +} + +ATOMLogo::ATOMLogo(const std::string &uri) : myUri(uri) { +} + + + +ATOMPublished::ATOMPublished() : ATOMDateConstruct(0) { +} + +ATOMPublished::ATOMPublished(int year) : ATOMDateConstruct(year) { +} + +ATOMPublished::ATOMPublished(int year, int month, int day) : ATOMDateConstruct(year, month, day) { +} + +ATOMPublished::ATOMPublished(int year, int month, int day, int hour, int minutes, int seconds) : + ATOMDateConstruct(year, month, day, hour, minutes, seconds) { +} + +ATOMPublished::ATOMPublished(int year, int month, int day, int hour, int minutes, int seconds, float sfract) : + ATOMDateConstruct(year, month, day, hour, minutes, seconds, sfract) { +} + +ATOMPublished::ATOMPublished(int year, int month, int day, int hour, int minutes, int seconds, float sfract, int tzhour, int tzminutes) : + ATOMDateConstruct(year, month, day, hour, minutes, seconds, sfract, tzhour, tzminutes) { +} + + + +ATOMUpdated::ATOMUpdated() : ATOMDateConstruct(0) { +} + +ATOMUpdated::ATOMUpdated(int year) : ATOMDateConstruct(year) { +} + +ATOMUpdated::ATOMUpdated(int year, int month, int day) : ATOMDateConstruct(year, month, day) { +} + +ATOMUpdated::ATOMUpdated(int year, int month, int day, int hour, int minutes, int seconds) : + ATOMDateConstruct(year, month, day, hour, minutes, seconds) { +} + +ATOMUpdated::ATOMUpdated(int year, int month, int day, int hour, int minutes, int seconds, float sfract) : + ATOMDateConstruct(year, month, day, hour, minutes, seconds, sfract) { +} + +ATOMUpdated::ATOMUpdated(int year, int month, int day, int hour, int minutes, int seconds, float sfract, int tzhour, int tzminutes) : + ATOMDateConstruct(year, month, day, hour, minutes, seconds, sfract, tzhour, tzminutes) { +} + + diff --git a/fbreader/src/network/atom/ATOMMetadata.h b/fbreader/src/network/atom/ATOMMetadata.h new file mode 100644 index 0000000..3fb7619 --- /dev/null +++ b/fbreader/src/network/atom/ATOMMetadata.h @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __ATOMMETADATA_H__ +#define __ATOMMETADATA_H__ + +#include "ATOMConstructs.h" + + +class ATOMConstants { + +private: + ATOMConstants(); + +public: + static const std::string TYPE_TEXT; + static const std::string TYPE_HTML; + static const std::string TYPE_XHTML; + static const std::string TYPE_DEFAULT; + + static const std::string REL_ALTERNATE; + static const std::string REL_RELATED; + static const std::string REL_SELF; + static const std::string REL_ENCLOSURE; + static const std::string REL_VIA; +}; + + + + + +class ATOMAuthor : public ATOMPersonConstruct { + +public: + ATOMAuthor(); + ATOMAuthor(const std::string &name); +}; + + + +class ATOMCategory : public ATOMCommonAttributes { + +public: + static const std::string TERM; + static const std::string SCHEME; + static const std::string LABEL; + +public: + ATOMCategory(); + ATOMCategory(const std::string &termStr); + +public: + std::string &term() { return attributes()[TERM]; } + std::string &scheme() { return attributes()[SCHEME]; } + std::string &label() { return attributes()[LABEL]; } + + void readAttributes(const std::map<std::string, std::string> &attributes); +}; + + + +class ATOMContributor : public ATOMPersonConstruct { + +public: + ATOMContributor(); + ATOMContributor(const std::string &name); +}; + + + +class ATOMGenerator : public ATOMCommonAttributes { + +public: + static const std::string URI; + static const std::string VERSION_ATT; + +public: + ATOMGenerator(); + ATOMGenerator(const std::string &text); + +public: + const std::string &text() const { return myText; } + void setText(const std::string &text) { myText = text; } + + std::string &uri() { return attributes()[URI]; } + std::string &version() { return attributes()[VERSION_ATT]; } + + void readAttributes(const std::map<std::string, std::string> &attributes); + +private: + std::string myText; +}; + + + +class ATOMIcon : public ATOMCommonAttributes { + +public: + ATOMIcon(); + ATOMIcon(const std::string &uri); + +public: + const std::string &uri() const { return myUri; } + void setUri(const std::string &uri) { myUri = uri; } + +private: + std::string myUri; +}; + + + +class ATOMId : public ATOMCommonAttributes { + +public: + ATOMId(); + ATOMId(const std::string &uri); + + const ATOMId &operator = (const ATOMId &id); + + bool operator == (const ATOMId &id) const; + bool operator != (const ATOMId &id) const; + +public: + const std::string &uri() const { return myUri; } + void setUri(const std::string &uri) { myUri = uri; } + +private: + std::string myUri; +}; + +inline const ATOMId &ATOMId::operator = (const ATOMId &id) { myUri = id.myUri; return *this; } +inline bool ATOMId::operator == (const ATOMId &id) const { return myUri == id.myUri; } +inline bool ATOMId::operator != (const ATOMId &id) const { return myUri != id.myUri; } + + + +class ATOMLink : public ATOMCommonAttributes { + +public: + static const std::string HREF; + static const std::string REL; + static const std::string TYPE; + static const std::string HREFLANG; + static const std::string TITLE; + static const std::string LENGTH; + +public: + ATOMLink(); + ATOMLink(const std::string &hrefStr); + ATOMLink(const std::string &hrefStr, const std::string &relStr); + ATOMLink(const std::string &hrefStr, const std::string &relStr, const std::string &typeStr); + ATOMLink(const std::string &hrefStr, const std::string &relStr, const std::string &typeStr, const std::string &titleStr); + +public: + std::string &href() { return attributes()[HREF]; } + std::string &rel() { return attributes()[REL]; } + std::string &type() { return attributes()[TYPE]; } + std::string &hreflang() { return attributes()[HREFLANG]; } + std::string &title() { return attributes()[TITLE]; } + std::string &length() { return attributes()[LENGTH]; } + + void readAttributes(const std::map<std::string, std::string> &attributes); +}; + + + +class ATOMLogo : public ATOMCommonAttributes { + +public: + ATOMLogo(); + ATOMLogo(const std::string &uri); + +public: + const std::string &uri() const { return myUri; } + void setUri(const std::string &uri) { myUri = uri; } + +private: + std::string myUri; +}; + + +class ATOMPublished : public ATOMDateConstruct { + +public: + ATOMPublished(); + ATOMPublished(int year); + ATOMPublished(int year, int month, int day); + ATOMPublished(int year, int month, int day, int hour, int minutes, int seconds); + ATOMPublished(int year, int month, int day, int hour, int minutes, int seconds, float sfract); + ATOMPublished(int year, int month, int day, int hour, int minutes, int seconds, float sfract, int tzhour, int tzminutes); +}; + +class ATOMUpdated : public ATOMDateConstruct { + +public: + ATOMUpdated(); + ATOMUpdated(int year); + ATOMUpdated(int year, int month, int day); + ATOMUpdated(int year, int month, int day, int hour, int minutes, int seconds); + ATOMUpdated(int year, int month, int day, int hour, int minutes, int seconds, float sfract); + ATOMUpdated(int year, int month, int day, int hour, int minutes, int seconds, float sfract, int tzhour, int tzminutes); +}; + + +#endif /* ATOMMETADATA */ diff --git a/fbreader/src/network/authentication/NetworkAuthenticationManager.cpp b/fbreader/src/network/authentication/NetworkAuthenticationManager.cpp new file mode 100644 index 0000000..137388f --- /dev/null +++ b/fbreader/src/network/authentication/NetworkAuthenticationManager.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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 "NetworkAuthenticationManager.h" + +#include "../NetworkLink.h" +#include "../NetworkErrors.h" + +NetworkAuthenticationManager::NetworkAuthenticationManager(const NetworkLink &link) : + Link(link), + UserNameOption(ZLCategoryKey::NETWORK, link.getSiteName(), "userName", ""), + SkipIPOption(ZLCategoryKey::NETWORK, link.getSiteName(), "skipIP", true) { +} + +NetworkAuthenticationManager::~NetworkAuthenticationManager() { +} + +bool NetworkAuthenticationManager::needsInitialization() { + return false; +} + +std::string NetworkAuthenticationManager::initialize(shared_ptr<ZLNetworkRequest::Listener> listener) { + listener->finished(); + return NetworkErrors::errorMessage(NetworkErrors::ERROR_UNSUPPORTED_OPERATION); +} + +bool NetworkAuthenticationManager::needPurchase(const NetworkBookItem &) { + return true; +} + +std::string NetworkAuthenticationManager::purchaseBook(const NetworkBookItem &, shared_ptr<ZLNetworkRequest::Listener> listener) { + std::string error = NetworkErrors::errorMessage(NetworkErrors::ERROR_UNSUPPORTED_OPERATION); + listener->finished(error); + return error; +} + + +std::string NetworkAuthenticationManager::topupAccountLink() { + return ""; +} + +std::string NetworkAuthenticationManager::currentAccount() { + return ""; +} + +bool NetworkAuthenticationManager::skipIPSupported() { + return false; +} + +bool NetworkAuthenticationManager::registrationSupported() { + return false; +} + +std::string NetworkAuthenticationManager::registerUser(const std::string &, const std::string &, const std::string &) { + return NetworkErrors::errorMessage(NetworkErrors::ERROR_UNSUPPORTED_OPERATION); +} + +bool NetworkAuthenticationManager::passwordRecoverySupported() { + return false; +} + +std::string NetworkAuthenticationManager::recoverPassword(const std::string &) { + return NetworkErrors::errorMessage(NetworkErrors::ERROR_UNSUPPORTED_OPERATION); +} diff --git a/fbreader/src/network/authentication/NetworkAuthenticationManager.h b/fbreader/src/network/authentication/NetworkAuthenticationManager.h new file mode 100644 index 0000000..75ae9dd --- /dev/null +++ b/fbreader/src/network/authentication/NetworkAuthenticationManager.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __NETWORKAUTHENTICATIONMANAGER_H__ +#define __NETWORKAUTHENTICATIONMANAGER_H__ + +#include <shared_ptr.h> +#include <ZLOptions.h> +#include <ZLBoolean3.h> + +#include "../NetworkItems.h" +#include "../BookReference.h" + +class NetworkLink; + +class NetworkAuthenticationManager { + +public: + NetworkAuthenticationManager(const NetworkLink &link); + virtual ~NetworkAuthenticationManager(); + +public: + const NetworkLink &Link; + ZLStringOption UserNameOption; + ZLBooleanOption SkipIPOption; + +public: + struct AuthenticationStatus { + const ZLBoolean3 Status; + const std::string Message; + + AuthenticationStatus(bool status); + AuthenticationStatus(const std::string &msg); + }; + + virtual AuthenticationStatus isAuthorised(shared_ptr<ZLNetworkRequest::Listener> listener = 0) = 0; + virtual std::string authorise(const std::string &pwd, shared_ptr<ZLNetworkRequest::Listener> listener) = 0; // returns error message + virtual void logOut() = 0; + + virtual bool skipIPSupported(); + + virtual shared_ptr<BookReference> downloadReference(const NetworkBookItem &book) = 0; + +public: // Account specific methods (can be called only if authorised!!!) + virtual const std::string ¤tUserName() = 0; + virtual bool needsInitialization(); + virtual std::string initialize(shared_ptr<ZLNetworkRequest::Listener> listener); // returns error message + virtual bool needPurchase(const NetworkBookItem &book); // returns true if link must be purchased before downloading + virtual std::string purchaseBook(const NetworkBookItem &, shared_ptr<ZLNetworkRequest::Listener> listener); // returns error message + + virtual std::string topupAccountLink(); + virtual std::string currentAccount(); + + virtual const NetworkItem::List &purchasedBooks() const = 0; + +public: // new User Registration + virtual bool registrationSupported(); + virtual std::string registerUser(const std::string &login, const std::string &password, const std::string &email); + +public: // Password Recovery + virtual bool passwordRecoverySupported(); + virtual std::string recoverPassword(const std::string &email); + +private: // disable copying + NetworkAuthenticationManager(const NetworkAuthenticationManager &); + const NetworkAuthenticationManager &operator = (const NetworkAuthenticationManager &); +}; + +inline NetworkAuthenticationManager::AuthenticationStatus::AuthenticationStatus(bool status) : Status(status ? B3_TRUE : B3_FALSE) {} +inline NetworkAuthenticationManager::AuthenticationStatus::AuthenticationStatus(const std::string &msg) : Status(B3_UNDEFINED), Message(msg) {} + +#endif /* __NETWORKAUTHENTICATIONMANAGER_H__ */ diff --git a/fbreader/src/network/authentication/litres/LitResAuthenticationDataParser.cpp b/fbreader/src/network/authentication/litres/LitResAuthenticationDataParser.cpp new file mode 100644 index 0000000..b1b6c69 --- /dev/null +++ b/fbreader/src/network/authentication/litres/LitResAuthenticationDataParser.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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 "LitResAuthenticationDataParser.h" + + +static const std::string TAG_AUTHORIZATION_OK = "catalit-authorization-ok"; +static const std::string TAG_AUTHORIZATION_FAILED = "catalit-authorization-failed"; + +static const std::string TAG_PURCHASE_OK = "catalit-purchase-ok"; +static const std::string TAG_PURCHASE_FAILED = "catalit-purchase-failed"; + +static const std::string TAG_DOWNLOAD_FAILED = "catalit-download-failed"; + +static const std::string TAG_REGISTRATION_FAILED = "catalit-registration-failed"; + +static const std::string TAG_PASSWORD_RECOVERY_OK = "catalit-pass-recover-ok"; +static const std::string TAG_PASSWORD_RECOVERY_FAILED = "catalit-pass-recover-failed"; + +LitResAuthenticationDataParser::LitResAuthenticationDataParser() { +} + +void LitResAuthenticationDataParser::startElementHandler(const char *tag, const char **attributes) { + myAttributes.clear(); + while (*attributes != 0) { + std::string name(*attributes++); + if (*attributes == 0) { + break; + } + std::string value(*attributes++); + myAttributes.insert(std::make_pair(name, value)); + } + processTag(tag); +} + + + + + +LitResLoginDataParser::LitResLoginDataParser(std::string &firstName, std::string &lastName, std::string &sid) : + myFirstName(firstName), myLastName(lastName), mySid(sid) { +} + +void LitResLoginDataParser::processTag(const std::string &tag) { + if (TAG_AUTHORIZATION_FAILED == tag) { + setErrorCode(NetworkErrors::ERROR_AUTHENTICATION_FAILED); + } else if (TAG_AUTHORIZATION_OK == tag) { + myFirstName = attributes()["first-name"]; + myLastName = attributes()["first-name"]; + mySid = attributes()["sid"]; + } +} + + +LitResPurchaseDataParser::LitResPurchaseDataParser(std::string &account, std::string &bookId) : + myAccount(account), myBookId(bookId) { +} + +void LitResPurchaseDataParser::processTag(const std::string &tag) { + if (TAG_AUTHORIZATION_FAILED == tag) { + setErrorCode(NetworkErrors::ERROR_AUTHENTICATION_FAILED); + } else { + myAccount = attributes()["account"]; + myBookId = attributes()["art"]; + if (TAG_PURCHASE_OK == tag) { + // nop + } else if (TAG_PURCHASE_FAILED == tag) { + const std::string &error = attributes()["error"]; + if ("1" == error) { + setErrorCode(NetworkErrors::ERROR_PURCHASE_NOT_ENOUGH_MONEY); + } else if ("2" == error) { + setErrorCode(NetworkErrors::ERROR_PURCHASE_MISSING_BOOK); + } else if ("3" == error) { + setErrorCode(NetworkErrors::ERROR_PURCHASE_ALREADY_PURCHASED); + } else { + setErrorCode(NetworkErrors::ERROR_INTERNAL); + } + } + } +} + + +/*LitResDownloadErrorDataParser::LitResDownloadErrorDataParser() { +} + +void LitResDownloadErrorDataParser::processTag(const std::string &tag) { + if (TAG_AUTHORIZATION_FAILED == tag) { + setErrorCode(NetworkErrors::ERROR_AUTHENTICATION_FAILED); + } else { + if (TAG_DOWNLOAD_FAILED == tag) { + const std::string &error = attributes()["error"]; + if ("1" == error) { + setErrorCode(NetworkErrors::ERROR_BOOK_NOT_PURCHASED); + } else if ("2" == error) { + setErrorCode(NetworkErrors::ERROR_DOWNLOAD_LIMIT_EXCEEDED); + } else { + setErrorCode(NetworkErrors::ERROR_INTERNAL); + } + } + } +}*/ + + +LitResRegisterUserDataParser::LitResRegisterUserDataParser(std::string &sid) : mySid(sid) { +} + +void LitResRegisterUserDataParser::processTag(const std::string &tag) { + if (TAG_REGISTRATION_FAILED == tag) { + const std::string &error = attributes()["error"]; + if ("1" == error) { + setErrorCode(NetworkErrors::ERROR_LOGIN_ALREADY_TAKEN); + } else if ("2" == error) { + setErrorCode(NetworkErrors::ERROR_LOGIN_WAS_NOT_SPECIFIED); + } else if ("3" == error) { + setErrorCode(NetworkErrors::ERROR_PASSWORD_WAS_NOT_SPECIFIED); + } else if ("4" == error) { + setErrorCode(NetworkErrors::ERROR_INVALID_EMAIL); + } else if ("5" == error) { + setErrorCode(NetworkErrors::ERROR_TOO_MANY_REGISTRATIONS); + } else { + setErrorCode(NetworkErrors::ERROR_INTERNAL); + } + } else if (TAG_AUTHORIZATION_OK == tag) { + mySid = attributes()["sid"]; + } +} + + +void LitResPasswordRecoveryDataParser::processTag(const std::string &tag) { + if (TAG_PASSWORD_RECOVERY_FAILED == tag) { + const std::string &error = attributes()["error"]; + if ("1" == error) { + setErrorCode(NetworkErrors::ERROR_NO_USER_EMAIL); + } else if ("2" == error) { + setErrorCode(NetworkErrors::ERROR_EMAIL_WAS_NOT_SPECIFIED); + } else { + setErrorCode(NetworkErrors::ERROR_INTERNAL); + } + } else if (TAG_PASSWORD_RECOVERY_OK == tag) { + // NOP + } +} diff --git a/fbreader/src/network/authentication/litres/LitResAuthenticationDataParser.h b/fbreader/src/network/authentication/litres/LitResAuthenticationDataParser.h new file mode 100644 index 0000000..60baa02 --- /dev/null +++ b/fbreader/src/network/authentication/litres/LitResAuthenticationDataParser.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __LITRESAUTHENTICATIONDATAPARSER_H__ +#define __LITRESAUTHENTICATIONDATAPARSER_H__ + +#include <ZLXMLReader.h> + +#include "../../NetworkErrors.h" + + +class LitResAuthenticationDataParser : public ZLXMLReader { + +public: + LitResAuthenticationDataParser(); + +private: + void startElementHandler(const char *tag, const char **attributes); + +protected: + void setErrorCode(const std::string &msg); + std::map<std::string, std::string> &attributes(); + + virtual void processTag(const std::string &tag) = 0; + +private: + std::map<std::string, std::string> myAttributes; +}; + +inline void LitResAuthenticationDataParser::setErrorCode(const std::string &msg) { setErrorMessage(NetworkErrors::errorMessage(msg)); } +inline std::map<std::string, std::string> &LitResAuthenticationDataParser::attributes() { return myAttributes; } + + +class LitResLoginDataParser : public LitResAuthenticationDataParser { + +public: + LitResLoginDataParser(std::string &firstName, std::string &lastName, std::string &sid); + +private: + void processTag(const std::string &tag); + +private: + std::string &myFirstName; + std::string &myLastName; + std::string &mySid; +}; + + +class LitResPurchaseDataParser : public LitResAuthenticationDataParser { + +public: + LitResPurchaseDataParser(std::string &account, std::string &bookId); + +private: + void processTag(const std::string &tag); + +private: + std::string &myAccount; + std::string &myBookId; +}; + + +/*class LitResDownloadErrorDataParser : public LitResAuthenticationDataParser { + +public: + LitResDownloadErrorDataParser(); + +private: + void processTag(const std::string &tag); + +};*/ + +class LitResRegisterUserDataParser : public LitResAuthenticationDataParser { + +public: + LitResRegisterUserDataParser(std::string &sid); + +private: + void processTag(const std::string &tag); + +private: + std::string &mySid; +}; + +class LitResPasswordRecoveryDataParser : public LitResAuthenticationDataParser { + +private: + void processTag(const std::string &tag); +}; + +#endif /* __LITRESAUTHENTICATIONDATAPARSER_H__ */ 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 <[email protected]> + * + * 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()); +} + diff --git a/fbreader/src/network/authentication/litres/LitResAuthenticationManager.h b/fbreader/src/network/authentication/litres/LitResAuthenticationManager.h new file mode 100644 index 0000000..6aefa6d --- /dev/null +++ b/fbreader/src/network/authentication/litres/LitResAuthenticationManager.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __LITRESAUTHENTICATIONMANAGER_H__ +#define __LITRESAUTHENTICATIONMANAGER_H__ + +#include <set> + +#include <ZLNetworkRequest.h> +#include <ZLUserData.h> + +#include "../NetworkAuthenticationManager.h" +#include "../../NetworkItems.h" + +class LitResAuthenticationManager : public NetworkAuthenticationManager { + +public: + LitResAuthenticationManager(const NetworkLink &link); + +public: + AuthenticationStatus isAuthorised(shared_ptr<ZLNetworkRequest::Listener> listener = 0); + std::string authorise(const std::string &pwd, shared_ptr<ZLNetworkRequest::Listener> listener); + void logOut(); + bool skipIPSupported(); + + const std::string ¤tUserName(); + bool needsInitialization(); + std::string initialize(shared_ptr<ZLNetworkRequest::Listener> listener); + bool needPurchase(const NetworkBookItem &book); + std::string purchaseBook(const NetworkBookItem &, shared_ptr<ZLNetworkRequest::Listener> listener); + shared_ptr<BookReference> downloadReference(const NetworkBookItem &book); + + std::string topupAccountLink(); + std::string currentAccount(); + + std::string reloadPurchasedBooks(shared_ptr<ZLNetworkRequest::Listener> listener); + void collectPurchasedBooks(NetworkItem::List &list); + const std::set<std::string> &getPurchasedIds() const; + const NetworkItem::List &purchasedBooks() const; + +private: + void onAuthorised(ZLUserDataHolder &data, const std::string &error); + void onBookPurchased(ZLUserDataHolder &data, const std::string &error); + void onBooksLoaded(ZLUserDataHolder &data, const std::string &error); + void onAccountReceived(ZLUserDataHolder &data, const std::string &error); + void onBooksReloaded(ZLUserDataHolder &data, const std::string &error); + +private: + shared_ptr<ZLNetworkRequest> loadPurchasedBooks(std::set<std::string> &purchasedBooksIds, NetworkItem::List &purchasedBooksList); + void loadPurchasedBooksOnError(std::set<std::string> &purchasedBooksIds, NetworkItem::List &purchasedBooksList); + void loadPurchasedBooksOnSuccess(std::set<std::string> &purchasedBooksIds, NetworkItem::List &purchasedBooksList); + + shared_ptr<ZLNetworkRequest> loadAccount(std::string &dummy1); + void loadAccountOnError(); + void loadAccountOnSuccess(); + +public: // new User Registration + bool registrationSupported(); + std::string registerUser(const std::string &login, const std::string &password, const std::string &email); + +public: // Password Recovery + bool passwordRecoverySupported(); + std::string recoverPassword(const std::string &email); + +private: + bool mySidChecked; + + ZLStringOption mySidUserNameOption; + ZLStringOption mySidOption; + + std::string myInitializedDataSid; + std::set<std::string> myPurchasedBooksIds; + NetworkItem::List myPurchasedBooksList; + std::string myAccount; +}; + +#endif /* __LITRESAUTHENTICATIONMANAGER_H__ */ diff --git a/fbreader/src/network/litres/LitResAuthorsItem.cpp b/fbreader/src/network/litres/LitResAuthorsItem.cpp new file mode 100644 index 0000000..ece7438 --- /dev/null +++ b/fbreader/src/network/litres/LitResAuthorsItem.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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 <ZLNetworkManager.h> + +#include "../NetworkLink.h" +#include "../NetworkComparators.h" +#include "../NetworkErrors.h" +#include "../NetworkItems.h" + +#include "LitResUtil.h" +#include "LitResAuthorsParser.h" +#include "LitResBooksFeedItem.h" + +#include "LitResAuthorsItem.h" + +LitResAuthorsItem::LitResAuthorsItem( + const NetworkLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility, + int flags +) : NetworkCatalogItem( + link, + title, + summary, + urlByType, + accessibility, + flags +) { +} + +class LitResAuthorsItemRunnable : public ZLRunnable { +public: + LitResAuthorsItemRunnable(LitResAuthorsItem *item, NetworkItem::List &children) : myItem(item), myChildren(children) { } + void run() { + myItem->fillChildrenWithAuthors(myChildren, myItem->myAuthorsList); + } +private: + LitResAuthorsItem *myItem; + NetworkItem::List &myChildren; +}; + +std::string LitResAuthorsItem::loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener) { + //TODO maybe add sid parameter if possible + //(at LitRes API documentation it said that's adding sid _always_ is a good practice) + + myAuthorsList.clear(); + shared_ptr<ZLNetworkRequest> data = ZLNetworkManager::Instance().createXMLParserRequest( + getCatalogUrl(), + new LitResAuthorsParser(myAuthorsList), + new LitResAuthorsItemRunnable(this, children) + ); + data->setListener(listener); + return ZLNetworkManager::Instance().performAsync(data); +} + +void LitResAuthorsItem::fillChildrenWithAuthors(NetworkItem::List &children, const LitResAuthorsParser::AuthorsList &authors) { + for (std::size_t i = 0; i < authors.size(); ++i) { + const LitResAuthorsParser::LitresAuthorData &author = authors.at(i); + + UrlInfoCollection urlByType = URLByType; + urlByType[NetworkItem::URL_CATALOG] = LitResUtil::generateBooksByAuthorUrl(author.Id); + //TODO add icon change for one author here + //urlByType[NetworkItem::URL_COVER] = + children.push_back(new LitResBooksFeedItem( + true, + Link, + author.DisplayName, + getSubtitle(author), + urlByType, + NetworkCatalogItem::ALWAYS, + NetworkCatalogItem::FLAG_GROUP_MORE_THAN_1_BOOK_BY_SERIES + )); + } +} + +std::string LitResAuthorsItem::getSubtitle(const LitResAuthorsParser::LitresAuthorData &author) { + static const std::string SPACE = " "; + std::string subtitle = author.FirstName; + if (!author.MiddleName.empty()) { + if (!subtitle.empty()) { + subtitle += SPACE; + } + subtitle += author.MiddleName; + } + if (!author.LastName.empty()) { + if (!subtitle.empty()) { + subtitle += SPACE; + } + subtitle += author.LastName; + } + return subtitle; +} diff --git a/fbreader/src/network/litres/LitResAuthorsItem.h b/fbreader/src/network/litres/LitResAuthorsItem.h new file mode 100644 index 0000000..31847f4 --- /dev/null +++ b/fbreader/src/network/litres/LitResAuthorsItem.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __LITRESAUTHORSITEM_H__ +#define __LITRESAUTHORSITEM_H__ + +#include "../NetworkItems.h" + +#include "LitResAuthorsParser.h" + +class LitResAuthorsItem : public NetworkCatalogItem { + +public: + LitResAuthorsItem( + const NetworkLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility, + int flags = FLAGS_DEFAULT + ); + +protected: + void fillChildrenWithAuthors(NetworkItem::List &children, const LitResAuthorsParser::AuthorsList &authors); + std::string loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener); + + static std::string getSubtitle(const LitResAuthorsParser::LitresAuthorData &author); + +private: + LitResAuthorsParser::AuthorsList myAuthorsList; + +friend class LitResAuthorsItemRunnable; +}; + +#endif /* __LITRESAUTHORSITEM_H__ */ diff --git a/fbreader/src/network/litres/LitResAuthorsParser.cpp b/fbreader/src/network/litres/LitResAuthorsParser.cpp new file mode 100644 index 0000000..453ffb5 --- /dev/null +++ b/fbreader/src/network/litres/LitResAuthorsParser.cpp @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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 <cstdlib> + +#include <ZLUnicodeUtil.h> + +#include "../NetworkLink.h" +#include "LitResGenre.h" +#include "LitResUtil.h" + +#include "LitResAuthorsParser.h" + +static const std::string TAG_CATALOG = "catalit-persons"; +static const std::string TAG_SUBJECT = "subject"; +static const std::string TAG_TITLE = "title"; +static const std::string TAG_MAIN = "main"; +static const std::string TAG_FIRST_NAME = "first-name"; +static const std::string TAG_MIDDLE_NAME = "middle-name"; +static const std::string TAG_LAST_NAME = "last-name"; + +std::string LitResAuthorsParser::stringAttributeValue(const char **attributes, const char *name) { + if (attributes == 0) { + return std::string(); + } + const char *value = attributeValue(attributes, name); + return value != 0 ? value : std::string(); +} + +LitResAuthorsParser::LitResAuthorsParser(AuthorsList &authors) : myAuthors(authors) { + myState = START; +} + + +void LitResAuthorsParser::startElementHandler(const char *tag, const char **attributes) { + processState(tag, false, attributes); + myState = getNextState(tag, false); + myBuffer.clear(); +} + +void LitResAuthorsParser::endElementHandler(const char *tag) { + processState(tag, true, 0); + myState = getNextState(tag, true); + myBuffer.clear(); +} + +void LitResAuthorsParser::characterDataHandler(const char *data, std::size_t len) { + myBuffer.append(data, len); +} + +void LitResAuthorsParser::processState(const std::string &tag, bool closed, const char **attributes) { + switch(myState) { + case START: + break; + case CATALOG: + if (!closed && TAG_SUBJECT == tag) { + myAuthorId = stringAttributeValue(attributes, "id"); + } + break; + case SUBJECT: + if (closed && TAG_SUBJECT == tag) { + LitresAuthorData litresAuthor; + litresAuthor.Id = myAuthorId; + litresAuthor.DisplayName = myAuthorDisplayName; + litresAuthor.FirstName = myAuthorFirstName; + litresAuthor.MiddleName = myAuthorMiddleName; + litresAuthor.LastName = myAuthorLastName; + litresAuthor.SortKey = ZLUnicodeUtil::toLower(myAuthorLastName); + + myAuthors.push_back(litresAuthor); + myAuthorId.clear(); + myAuthorDisplayName.clear(); + myAuthorFirstName.clear(); + myAuthorMiddleName.clear(); + myAuthorLastName.clear(); + } + break; + case TITLE: + break; + case MAIN: + if (closed && TAG_MAIN == tag) { + ZLUnicodeUtil::utf8Trim(myBuffer); + myAuthorDisplayName = myBuffer; + } + break; + case FIRST_NAME: + if (closed && TAG_FIRST_NAME == tag) { + ZLUnicodeUtil::utf8Trim(myBuffer); + myAuthorFirstName = myBuffer; + } + break; + case MIDDLE_NAME: + if (closed && TAG_MIDDLE_NAME == tag) { + ZLUnicodeUtil::utf8Trim(myBuffer); + myAuthorMiddleName = myBuffer; + } + break; + case LAST_NAME: + if (closed && TAG_LAST_NAME == tag) { + ZLUnicodeUtil::utf8Trim(myBuffer); + myAuthorLastName = myBuffer; + } + break; + } +} + +LitResAuthorsParser::State LitResAuthorsParser::getNextState(const std::string &tag, bool closed) { + switch(myState) { + case START: + if (!closed && TAG_CATALOG == tag) { + return CATALOG; + } + break; + case CATALOG: + if (!closed) { + if (TAG_SUBJECT == tag) { + return SUBJECT; + } + } else { + if (TAG_CATALOG == tag) { + return START; + } + } + break; + case SUBJECT: + if (!closed) { + if (TAG_TITLE == tag) { + return TITLE; + } + } else { + if (TAG_SUBJECT == tag) { + return CATALOG; + } + } + break; + case TITLE: + if (!closed) { + if (TAG_MAIN == tag) { + return MAIN; + } + } else { + if (TAG_TITLE == tag) { + return FIRST_NAME; + } + } + break; + case MAIN: + if (closed && TAG_MAIN == tag) { + return TITLE; + } + break; + case FIRST_NAME: + if (closed && TAG_FIRST_NAME == tag) { + return MIDDLE_NAME; + } + break; + case MIDDLE_NAME: + if (closed && TAG_MIDDLE_NAME == tag) { + return LAST_NAME; + } + break; + case LAST_NAME: + if (closed && TAG_LAST_NAME == tag) { + return SUBJECT; + } + break; + } + return myState; +} diff --git a/fbreader/src/network/litres/LitResAuthorsParser.h b/fbreader/src/network/litres/LitResAuthorsParser.h new file mode 100644 index 0000000..ead137d --- /dev/null +++ b/fbreader/src/network/litres/LitResAuthorsParser.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __LITRESAUTHORSPARSER_H__ +#define __LITRESAUTHORSPARSER_H__ + +#include <vector> +#include <map> + +#include <ZLXMLReader.h> + +#include "../NetworkItems.h" + +class NetworkLink; +struct LitResGenre; +class NetworkAuthenticationManager; + +class LitResAuthorsParser : public ZLXMLReader { + +public: + struct LitresAuthorData { + std::string Id; + std::string DisplayName; + std::string FirstName; + std::string MiddleName; + std::string LastName; + std::string SortKey; + + bool operator< (const LitresAuthorData &authorData) const; + }; + typedef std::vector<LitresAuthorData> AuthorsList; + +public: + LitResAuthorsParser(AuthorsList &authors); + +private: + void startElementHandler(const char *tag, const char **attributes); + void endElementHandler(const char *tag); + void characterDataHandler(const char *text, std::size_t len); + +private: + enum State { + START, CATALOG, SUBJECT, TITLE, MAIN, FIRST_NAME, MIDDLE_NAME, LAST_NAME + }; + + std::string stringAttributeValue(const char **attributes, const char *name); + void processState(const std::string &tag, bool closed, const char **attributes); + State getNextState(const std::string &tag, bool closed); + +private: + AuthorsList &myAuthors; + + std::string myBuffer; + State myState; + + std::string myAuthorId; + std::string myAuthorDisplayName; + std::string myAuthorFirstName; + std::string myAuthorMiddleName; + std::string myAuthorLastName; +}; + +inline bool LitResAuthorsParser::LitresAuthorData::operator< (const LitresAuthorData &authorData) const { + return SortKey.compare(authorData.SortKey) < 0; +} + +#endif /* __LITRESAUTHORSPARSER_H__ */ diff --git a/fbreader/src/network/litres/LitResBookItem.cpp b/fbreader/src/network/litres/LitResBookItem.cpp new file mode 100644 index 0000000..cdc9306 --- /dev/null +++ b/fbreader/src/network/litres/LitResBookItem.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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 <ZLResource.h> +#include <ZLStringUtil.h> + +#include "LitResBooksFeedItem.h" +#include "LitResUtil.h" + +#include "LitResBookItem.h" + +LitResBookItem::LitResBookItem( + const NetworkLink &link, + const std::string &id, + unsigned int index, + const std::string &title, + const std::string &summary, + const std::string &language, + const std::string &date, + const std::vector<AuthorData> &authors, + const std::vector<std::string> &tags, + const std::string &seriesTitle, + unsigned int indexInSeries, + const UrlInfoCollection &urlByType, + const std::vector<shared_ptr<BookReference> > references, + const std::vector<std::string> authorIds +) : + NetworkBookItem(link, id, index, title, summary, language, date, authors, + tags, seriesTitle, indexInSeries, urlByType, references), + myAuthorIds(authorIds) +{ + +} + +std::vector<shared_ptr<NetworkItem> > LitResBookItem::getRelatedCatalogsItems() const { + std::vector<shared_ptr<NetworkItem> > items; + + UrlInfoCollection urlByType = URLByType; + + urlByType[URL_CATALOG] = LitResUtil::generateAlsoReadUrl(Id); + items.push_back(new LitResBooksFeedItem(false, Link, resource("alsoRead").value(), std::string(), urlByType)); + + for (std::size_t i = 0; i < myAuthorIds.size(); ++i) { + urlByType[URL_CATALOG] = LitResUtil::generateBooksByAuthorUrl(myAuthorIds.at(i)); + std::string title = ZLStringUtil::printf(resource("sameAuthor").value(), Authors.at(i).DisplayName); + items.push_back(new LitResBooksFeedItem(false, Link, title, std::string(), urlByType)); + } + + return items; +} + +const ZLResource &LitResBookItem::resource(const std::string &resourceKey) const { + return ZLResource::resource("networkView")["bookNode"][resourceKey]; +} diff --git a/fbreader/src/network/litres/LitResBookItem.h b/fbreader/src/network/litres/LitResBookItem.h new file mode 100644 index 0000000..129b6a6 --- /dev/null +++ b/fbreader/src/network/litres/LitResBookItem.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __LITRESBOOKITEM_H__ +#define __LITRESBOOKITEM_H__ + +#include "../NetworkItems.h" + +class LitResBookItem : public NetworkBookItem { +public: + LitResBookItem( + const NetworkLink &link, + const std::string &id, + unsigned int index, + const std::string &title, + const std::string &summary, + const std::string &language, + const std::string &date, + const std::vector<AuthorData> &authors, + const std::vector<std::string> &tags, + const std::string &seriesTitle, + unsigned int indexInSeries, + const UrlInfoCollection &urlByType, + const std::vector<shared_ptr<BookReference> > references, + const std::vector<std::string> authorIds + ); + + std::vector<shared_ptr<NetworkItem> > getRelatedCatalogsItems() const; + +protected: + const ZLResource &resource(const std::string &resourceKey) const; + +private: + std::vector<std::string> myAuthorIds; +}; + +#endif /* __LITRESBOOKITEM_H__ */ diff --git a/fbreader/src/network/litres/LitResBooksFeedItem.cpp b/fbreader/src/network/litres/LitResBooksFeedItem.cpp new file mode 100644 index 0000000..b597255 --- /dev/null +++ b/fbreader/src/network/litres/LitResBooksFeedItem.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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 <algorithm> + +#include <ZLNetworkManager.h> +#include <ZLNetworkUtil.h> +#include <ZLStringUtil.h> + +#include "../NetworkLink.h" +#include "../NetworkComparators.h" +#include "../NetworkErrors.h" +#include "../NetworkItems.h" + +#include "LitResUtil.h" +#include "LitResBooksFeedParser.h" + +#include "LitResBooksFeedItem.h" + +LitResBooksFeedItem::LitResBooksFeedItem( + bool shouldSort, + const NetworkLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility, + int flags +) : NetworkCatalogItem( + link, + title, + summary, + urlByType, + accessibility, + flags +), myShouldSort(shouldSort) { + +} + +void LitResBooksFeedItem::onDisplayItem() { +} + +class LitResBooksFeedItemRunnable : public ZLNetworkRequest::Listener { +public: + LitResBooksFeedItemRunnable(LitResBooksFeedItem &item, shared_ptr<ZLNetworkRequest> request, NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener) : + myItem(item), myChildren(children), myListener(listener) { + request->setListener(this); + ZLNetworkManager::Instance().performAsync(request); + } + + void finished(const std::string &error) { + if (error.empty()) { + ++myItem.myLoadingState.CurrentPage; + if (myItem.myShouldSort) { + std::sort(myChildren.begin(), myChildren.end(), NetworkBookItemComparator()); + } + } + myListener->finished(error); + } +private: + LitResBooksFeedItem &myItem; + NetworkItem::List &myChildren; + shared_ptr<ZLNetworkRequest::Listener> myListener; +}; + + +std::string LitResBooksFeedItem::loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener) { +// //TODO maybe add sid parameter if possible +// //(at LitRes API documentation it said that's adding sid _always_ is a good practice) + + myLoadingState.CurrentPage = 0; + myLoadingState.AllPagesCount = 1; + + shared_ptr<ZLNetworkRequest> request = getRequest(children); + new LitResBooksFeedItemRunnable(*this, request, children, listener); + return std::string(); +} + +bool LitResBooksFeedItem::supportsResumeLoading() { + return true; +} + +std::string LitResBooksFeedItem::resumeLoading(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener) { + shared_ptr<ZLNetworkRequest> request = getRequest(children); + if (request.isNull()) { + listener->finished(); + return std::string(); + } + new LitResBooksFeedItemRunnable(*this, request, children, listener); + return std::string(); +} + +shared_ptr<ZLNetworkRequest> LitResBooksFeedItem::getRequest(NetworkItem::List &children) { + if (myLoadingState.CurrentPage >= myLoadingState.AllPagesCount) { + return 0; + } + return ZLNetworkManager::Instance().createXMLParserRequest( + withLimitParameters(getCatalogUrl(), myLoadingState), + new LitResBooksFeedParser(Link, children, &myLoadingState) + ); +} + +std::string LitResBooksFeedItem::withLimitParameters(std::string query, const LoadingState &state) { + static const unsigned int ITEMS_PER_PAGE = 40; + unsigned int startItemNumber = (unsigned int)state.CurrentPage * ITEMS_PER_PAGE; + std::string params; + ZLStringUtil::appendNumber(params, startItemNumber); + params += ","; + ZLStringUtil::appendNumber(params, ITEMS_PER_PAGE); + ZLNetworkUtil::appendParameter(query, "limit", params); + return query; +} + diff --git a/fbreader/src/network/litres/LitResBooksFeedItem.h b/fbreader/src/network/litres/LitResBooksFeedItem.h new file mode 100644 index 0000000..8af7df2 --- /dev/null +++ b/fbreader/src/network/litres/LitResBooksFeedItem.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __LITRESBOOKFEEDITEM_H__ +#define __LITRESBOOKFEEDITEM_H__ + +#include "../NetworkItems.h" + +class LitResBooksFeedItem : public NetworkCatalogItem { + +public: + struct LoadingState { + int CurrentPage; + int AllPagesCount; + } myLoadingState; + +public: + LitResBooksFeedItem( + bool shouldSort, + const NetworkLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility = ALWAYS, + int flags = FLAGS_DEFAULT + ); + +private: + void onDisplayItem(); + std::string loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener); + bool supportsResumeLoading(); + std::string resumeLoading(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener); + +private: + shared_ptr<ZLNetworkRequest> getRequest(NetworkItem::List &children); + static std::string withLimitParameters(std::string url, const LoadingState &state); + +private: + bool myShouldSort; + +friend class LitResBooksFeedItemRunnable; +}; + +#endif /* __LITRESBOOKFEEDITEM_H__ */ diff --git a/fbreader/src/network/litres/LitResBooksFeedParser.cpp b/fbreader/src/network/litres/LitResBooksFeedParser.cpp new file mode 100644 index 0000000..970a8eb --- /dev/null +++ b/fbreader/src/network/litres/LitResBooksFeedParser.cpp @@ -0,0 +1,433 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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 <cstdlib> + +#include <ZLStringUtil.h> +#include <ZLUnicodeUtil.h> + +#include "LitResBooksFeedParser.h" +#include "LitResBookItem.h" +#include "LitResGenre.h" +#include "LitResUtil.h" +#include "../NetworkLink.h" + +static const std::string TAG_CATALOG = "catalit-fb2-books"; +static const std::string TAG_BOOK = "fb2-book"; +static const std::string TAG_TEXT_DESCRIPTION = "text_description"; +static const std::string TAG_HIDDEN = "hidden"; +static const std::string TAG_TITLE_INFO = "title-info"; +static const std::string TAG_GENRE = "genre"; +static const std::string TAG_AUTHOR = "author"; +static const std::string TAG_FIRST_NAME = "first-name"; +static const std::string TAG_MIDDLE_NAME = "middle-name"; +static const std::string TAG_LAST_NAME = "last-name"; +static const std::string TAG_AUTHOR_ID = "id"; +static const std::string TAG_BOOK_TITLE = "book-title"; +static const std::string TAG_ANNOTATION = "annotation"; +static const std::string TAG_DATE = "date"; +static const std::string TAG_SEQUENCE = "sequence"; +static const std::string TAG_LANGUAGE = "lang"; + +std::string LitResBooksFeedParser::stringAttributeValue(const char **attributes, const char *name) { + if (attributes == 0) { + return std::string(); + } + const char *value = attributeValue(attributes, name); + return value != 0 ? value : std::string(); +} + +LitResBooksFeedParser::LitResBooksFeedParser(const NetworkLink &link, NetworkItem::List &books, LitResBooksFeedItem::LoadingState *loadingState) : + myLink(link), + myBooks(books), + myIndex(0), + myLoadingState(loadingState) { + myState = START; +} + + +void LitResBooksFeedParser::startElementHandler(const char *tag, const char **attributes) { + processState(tag, false, attributes); + myState = getNextState(tag, false); + myBuffer.clear(); +} + +void LitResBooksFeedParser::endElementHandler(const char *tag) { + processState(tag, true, 0); + myState = getNextState(tag, true); + myBuffer.clear(); +} + +void LitResBooksFeedParser::characterDataHandler(const char *data, std::size_t len) { + myBuffer.append(data, len); +} + +void LitResBooksFeedParser::processState(const std::string &tag, bool closed, const char **attributes) { + switch(myState) { + case START: + if (!closed && TAG_CATALOG == tag) { + if (myLoadingState) { + myLoadingState->AllPagesCount = ZLStringUtil::stringToInteger(stringAttributeValue(attributes, "pages"), 1); + } + } + break; + case CATALOG: + if (!closed && TAG_BOOK == tag) { + myBookId = stringAttributeValue(attributes, "hub_id"); + myURLByType[NetworkItem::URL_COVER] = + stringAttributeValue(attributes, "cover_preview"); + myURLByType[NetworkItem::URL_FULL_COVER] = + stringAttributeValue(attributes, "cover"); + + std::string url = stringAttributeValue(attributes, "url"); + if (!url.empty()) { + myLink.rewriteUrl(url, true); // This code duplicates code in FBReader::openInBrowser and is not required + myURLByType[NetworkItem::URL_HTML_PAGE] = url; + } + + //TODO check if buying book works right + std::string price = BuyBookReference::price(stringAttributeValue(attributes, "price"), "RUB"); + myReferences.push_back(new BuyBookReference( + LitResUtil::generatePurchaseUrl(myLink, myBookId), + BookReference::FB2_ZIP, + BookReference::BUY, + price + )); + + std::string hasTrial = stringAttributeValue(attributes, "has_trial"); + if (!hasTrial.empty() && hasTrial != "0") { + myReferences.push_back(new BookReference( + LitResUtil::generateTrialUrl(myBookId), + BookReference::FB2_ZIP, + BookReference::DOWNLOAD_DEMO + )); + } + + myReferences.push_back(new BookReference( + LitResUtil::generateDownloadUrl(myBookId), + BookReference::FB2_ZIP, + BookReference::DOWNLOAD_FULL_CONDITIONAL + )); + } + break; + case BOOK: + if (closed && TAG_BOOK == tag) { + myBooks.push_back(new LitResBookItem( + myLink, + myBookId, + myIndex++, + myTitle, + mySummary, + myLanguage, + myDate, + myAuthors, + myTags, + mySeriesTitle, + myIndexInSeries, + myURLByType, + myReferences, + myAuthorsIds + )); + + myTitle.erase(); + mySummary.erase(); + myLanguage.erase(); + myDate.erase(); + mySeriesTitle.erase(); + myIndexInSeries = 0; + myAuthors.clear(); + myAuthorsIds.clear(); + myTags.clear(); + myURLByType.clear(); + myReferences.clear(); + } + break; + case BOOK_DESCRIPTION: + break; + case HIDDEN: + break; + case TITLE_INFO: + if (!closed) { + if (TAG_AUTHOR == tag) { + myAuthorFirstName.clear(); + myAuthorMiddleName.clear(); + myAuthorLastName.clear(); + } else if (TAG_SEQUENCE == tag) { + mySeriesTitle = stringAttributeValue(attributes, "name"); + if (!mySeriesTitle.empty()) { + const char *indexInSeries = attributeValue(attributes, "number"); + myIndexInSeries = indexInSeries != 0 ? std::atoi(indexInSeries) : 0; + } + } + } + break; + case AUTHOR: + if (closed && TAG_AUTHOR == tag) { + NetworkBookItem::AuthorData data; + if (!myAuthorFirstName.empty()) { + data.DisplayName.append(myAuthorFirstName); + } + if (!myAuthorMiddleName.empty()) { + if (!data.DisplayName.empty()) { + data.DisplayName.append(" "); + } + data.DisplayName.append(myAuthorMiddleName); + } + if (!myAuthorLastName.empty()) { + if (!data.DisplayName.empty()) { + data.DisplayName.append(" "); + } + data.DisplayName.append(myAuthorLastName); + } + data.SortKey = myAuthorLastName; + myAuthors.push_back(data); + myAuthorsIds.push_back(myAuthorId); + } + break; + case FIRST_NAME: + if (closed && TAG_FIRST_NAME == tag) { + ZLUnicodeUtil::utf8Trim(myBuffer); + myAuthorFirstName = myBuffer; + } + break; + case MIDDLE_NAME: + if (closed && TAG_MIDDLE_NAME == tag) { + ZLUnicodeUtil::utf8Trim(myBuffer); + myAuthorMiddleName = myBuffer; + } + break; + case LAST_NAME: + if (closed && TAG_LAST_NAME == tag) { + ZLUnicodeUtil::utf8Trim(myBuffer); + myAuthorLastName = myBuffer; + } + break; + case AUTHOR_ID: + if (closed && TAG_AUTHOR_ID == tag) { + ZLUnicodeUtil::utf8Trim(myBuffer); + myAuthorId = myBuffer; + } + break; + case GENRE: + if (closed && TAG_GENRE == tag) { + ZLUnicodeUtil::utf8Trim(myBuffer); + + const std::map<std::string,shared_ptr<LitResGenre> > &genresMap = + LitResGenreMap::Instance().genresMap(); + const std::map<shared_ptr<LitResGenre>,std::string> &genresTitles = + LitResGenreMap::Instance().genresTitles(); + + std::map<std::string, shared_ptr<LitResGenre> >::const_iterator it = genresMap.find(myBuffer); + if (it != genresMap.end()) { + std::map<shared_ptr<LitResGenre>, std::string>::const_iterator jt = genresTitles.find(it->second); + if (jt != genresTitles.end()) { + myTags.push_back(jt->second); + } + } + } + break; + case BOOK_TITLE: + if (closed && TAG_BOOK_TITLE == tag) { + ZLUnicodeUtil::utf8Trim(myBuffer); + myTitle = myBuffer; + } + break; + case ANNOTATION: + if (!closed) { + ZLUnicodeUtil::utf8Trim(myBuffer); + if (!myBuffer.empty()) { + mySummary.append(myBuffer); + mySummary.append(" "); + } + } else { + ZLUnicodeUtil::utf8Trim(myBuffer); + mySummary.append(myBuffer); + int size = mySummary.size(); + if (size > 0) { + if (TAG_ANNOTATION == tag) { + if (mySummary[size - 1] == '\n') { + mySummary.erase(size - 1); + } + } else if ("p" == tag) { + if (mySummary[size - 1] != '\n') { + mySummary.append("\n"); + } + } else { + if (!myBuffer.empty() && mySummary[size - 1] != '\n') { + mySummary.append(" "); + } + } + } + } + break; + case DATE: + if (closed && TAG_DATE == tag) { + ZLUnicodeUtil::utf8Trim(myBuffer); + myDate = myBuffer; + } + break; + case LANGUAGE: + if (closed && TAG_LANGUAGE == tag) { + ZLUnicodeUtil::utf8Trim(myBuffer); + myLanguage = myBuffer; + } + break; + } +} + +LitResBooksFeedParser::State LitResBooksFeedParser::getNextState(const std::string &tag, bool closed) { + switch(myState) { + case START: + if (!closed && TAG_CATALOG == tag) { + return CATALOG; + } + break; + case CATALOG: + if (!closed) { + if (TAG_BOOK == tag) { + return BOOK; + } + } else { + if (TAG_CATALOG == tag) { + return START; + } + } + break; + case BOOK: + if (!closed) { + if (TAG_TEXT_DESCRIPTION == tag) { + return BOOK_DESCRIPTION; + } + } else { + if (TAG_BOOK == tag) { + return CATALOG; + } + } + break; + case BOOK_DESCRIPTION: + if (!closed) { + if (TAG_HIDDEN == tag) { + return HIDDEN; + } + } else { + if (TAG_TEXT_DESCRIPTION == tag) { + return BOOK; + } + } + break; + case HIDDEN: + if (!closed) { + if (TAG_TITLE_INFO == tag) { + return TITLE_INFO; + } + } else { + if (TAG_HIDDEN == tag) { + return BOOK_DESCRIPTION; + } + } + break; + case TITLE_INFO: + if (!closed) { + if (TAG_GENRE == tag) { + return GENRE; + } else if (TAG_AUTHOR == tag) { + return AUTHOR; + } else if (TAG_BOOK_TITLE == tag) { + return BOOK_TITLE; + } else if (TAG_ANNOTATION == tag) { + return ANNOTATION; + } else if (TAG_DATE == tag) { + return DATE; + } else if (TAG_LANGUAGE == tag) { + return LANGUAGE; + } /*else if (TAG_SEQUENCE == tag) { + return SEQUENCE; // handled without state through attributes + }*/ + } else { + if (TAG_TITLE_INFO == tag) { + return HIDDEN; + } + } + break; + case AUTHOR: + if (!closed) { + if (TAG_FIRST_NAME == tag) { + return FIRST_NAME; + } else if (TAG_MIDDLE_NAME == tag) { + return MIDDLE_NAME; + } else if (TAG_LAST_NAME == tag) { + return LAST_NAME; + } else if (TAG_AUTHOR_ID == tag) { + return AUTHOR_ID; + } + } else { + if (TAG_AUTHOR == tag) { + return TITLE_INFO; + } + } + break; + case FIRST_NAME: + if (closed && TAG_FIRST_NAME == tag) { + return AUTHOR; + } + break; + case MIDDLE_NAME: + if (closed && TAG_MIDDLE_NAME == tag) { + return AUTHOR; + } + break; + case LAST_NAME: + if (closed && TAG_LAST_NAME == tag) { + return AUTHOR; + } + break; + case AUTHOR_ID: + if (closed && TAG_AUTHOR_ID == tag) { + return AUTHOR; + } + break; + case GENRE: + if (closed && TAG_GENRE == tag) { + return TITLE_INFO; + } + break; + case BOOK_TITLE: + if (closed && TAG_BOOK_TITLE == tag) { + return TITLE_INFO; + } + break; + case ANNOTATION: + if (closed && TAG_ANNOTATION == tag) { + return TITLE_INFO; + } + break; + case DATE: + if (closed && TAG_DATE == tag) { + return TITLE_INFO; + } + break; + case LANGUAGE: + if (closed && TAG_LANGUAGE == tag) { + return TITLE_INFO; + } + break; + } + return myState; +} + diff --git a/fbreader/src/network/litres/LitResBooksFeedParser.h b/fbreader/src/network/litres/LitResBooksFeedParser.h new file mode 100644 index 0000000..6f9a6dc --- /dev/null +++ b/fbreader/src/network/litres/LitResBooksFeedParser.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __LITRESBOOKSFEEDPARSER_H__ +#define __LITRESBOOKSFEEDPARSER_H__ + +#include <vector> +#include <map> + +#include <ZLXMLReader.h> + +#include "../NetworkItems.h" + +#include "LitResBooksFeedItem.h" + +class NetworkLink; +struct LitResGenre; +class NetworkAuthenticationManager; + +class LitResBooksFeedParser : public ZLXMLReader { + +public: + LitResBooksFeedParser(const NetworkLink &link, NetworkItem::List &books, LitResBooksFeedItem::LoadingState *state = 0); + +private: + void startElementHandler(const char *tag, const char **attributes); + void endElementHandler(const char *tag); + void characterDataHandler(const char *text, std::size_t len); + +private: + enum State { + START, CATALOG, BOOK, BOOK_DESCRIPTION, HIDDEN, TITLE_INFO, + GENRE, AUTHOR, FIRST_NAME, MIDDLE_NAME, LAST_NAME, AUTHOR_ID, BOOK_TITLE, + ANNOTATION, DATE, LANGUAGE, + }; + + std::string stringAttributeValue(const char **attributes, const char *name); + void processState(const std::string &tag, bool closed, const char **attributes); + State getNextState(const std::string &tag, bool closed); + +private: + const NetworkLink &myLink; + + NetworkItem::List &myBooks; + std::string myBuffer; + + unsigned int myIndex; + + State myState; + + std::string myBookId; + std::string myTitle; + std::string mySummary; + std::string myLanguage; + std::string myDate; + std::string mySeriesTitle; + int myIndexInSeries; + + std::string myAuthorFirstName; + std::string myAuthorMiddleName; + std::string myAuthorLastName; + std::string myAuthorId; + std::vector<NetworkBookItem::AuthorData> myAuthors; + std::vector<std::string> myAuthorsIds; + + std::vector<std::string> myTags; + NetworkItem::UrlInfoCollection myURLByType; + std::vector<shared_ptr<BookReference> > myReferences; + + LitResBooksFeedItem::LoadingState *myLoadingState; +}; + +#endif /* __LITRESBOOKSFEEDPARSER_H__ */ diff --git a/fbreader/src/network/litres/LitResBookshelfItem.cpp b/fbreader/src/network/litres/LitResBookshelfItem.cpp new file mode 100644 index 0000000..be931fe --- /dev/null +++ b/fbreader/src/network/litres/LitResBookshelfItem.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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 <algorithm> + +#include <ZLNetworkRequest.h> +#include <ZLExecutionUtil.h> + +#include "LitResBookshelfItem.h" +#include "../authentication/litres/LitResAuthenticationManager.h" + +#include "../NetworkLink.h" +#include "../NetworkComparators.h" +#include "../NetworkErrors.h" + +#include "SortedCatalogItem.h" + +LitResBookshelfItem::LitResBookshelfItem( + const NetworkLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility +) : NetworkCatalogItem( + link, + title, + summary, + urlByType, + accessibility +) { + myForceReload = false; +} + +void LitResBookshelfItem::onDisplayItem() { + myForceReload = false; +} + +class LitResBookshelfItemLoaderScope : public ZLUserData { +public: + LitResBookshelfItemLoaderScope(NetworkItem::List &children) : Children(children) {} + NetworkItem::List &Children; + shared_ptr<ZLNetworkRequest::Listener> listener; +}; + + +std::string LitResBookshelfItem::loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener) { + LitResAuthenticationManager &mgr = (LitResAuthenticationManager&)*Link.authenticationManager(); + if (mgr.isAuthorised().Status == B3_FALSE) { + listener->finished(NetworkErrors::errorMessage(NetworkErrors::ERROR_AUTHENTICATION_FAILED)); + return NetworkErrors::errorMessage(NetworkErrors::ERROR_AUTHENTICATION_FAILED); + } + + LitResBookshelfItemLoaderScope *scope = new LitResBookshelfItemLoaderScope(children); + scope->listener = listener; + + shared_ptr<ZLUserDataHolder> scopeData = new ZLUserDataHolder; + scopeData->addUserData("scope", scope); + if (myForceReload) { + mgr.reloadPurchasedBooks(ZLExecutionUtil::createListener(scopeData, this, &LitResBookshelfItem::onReloaded)); + return std::string(); + } + onReloaded(*scopeData, std::string()); + return std::string(); +} + +void LitResBookshelfItem::onReloaded(ZLUserDataHolder &data, const std::string &error) { + LitResBookshelfItemLoaderScope &scope = static_cast<LitResBookshelfItemLoaderScope&>(*data.getUserData("scope")); + LitResAuthenticationManager &mgr = static_cast<LitResAuthenticationManager&>(*Link.authenticationManager()); + myForceReload = true; + NetworkItem::List tmpChildren; + mgr.collectPurchasedBooks(tmpChildren); + std::sort(tmpChildren.begin(), tmpChildren.end(), NetworkBookItemComparator()); + + + NetworkItem::List &children = scope.Children; + + if (tmpChildren.size() <= 5) { + children.assign(tmpChildren.begin(), tmpChildren.end()); + std::sort(children.begin(), children.end(), NetworkBookItemComparator()); + } else { + children.push_back(SortedCatalogItem::create(*this, "byDate", tmpChildren, FLAG_SHOW_AUTHOR)); + children.push_back(SortedCatalogItem::create(*this, "byAuthor", tmpChildren, FLAG_GROUP_BY_AUTHOR, NetworkBookItemComparator())); + children.push_back(SortedCatalogItem::create(*this, "byTitle", tmpChildren, FLAG_SHOW_AUTHOR, NetworkBookItemByTitleComparator())); + SortedCatalogItem* bySeries = SortedCatalogItem::create(*this, "bySeries", tmpChildren, FLAG_SHOW_AUTHOR | FLAG_GROUP_BY_SERIES, + NetworkBookItemBySeriesComparator(), SortedCatalogItem::BySeriesFilter()); + + if (!bySeries->isEmpty()) { + children.push_back(bySeries); + } else { + delete bySeries; + } + } + + scope.listener->finished(error); +} diff --git a/fbreader/src/network/litres/LitResBookshelfItem.h b/fbreader/src/network/litres/LitResBookshelfItem.h new file mode 100644 index 0000000..22ea8d9 --- /dev/null +++ b/fbreader/src/network/litres/LitResBookshelfItem.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __LITRESBOOKSHELFITEM_H__ +#define __LITRESBOOKSHELFITEM_H__ + +#include <ZLResource.h> +#include <ZLExecutionUtil.h> + +#include "../NetworkComparators.h" +#include "../NetworkItems.h" + +class NetworkLink; + +class LitResBookshelfItem : public NetworkCatalogItem { + +public: + LitResBookshelfItem( + const NetworkLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility = ALWAYS + ); + +private: + void onDisplayItem(); + std::string loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener); + void onReloaded(ZLUserDataHolder &data, const std::string &error); + +private: + bool myForceReload; +}; + +#endif /* __LITRESBOOKSHELFITEM_H__ */ diff --git a/fbreader/src/network/litres/LitResByGenresItem.cpp b/fbreader/src/network/litres/LitResByGenresItem.cpp new file mode 100644 index 0000000..a9b6367 --- /dev/null +++ b/fbreader/src/network/litres/LitResByGenresItem.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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 <algorithm> + +#include <ZLNetworkManager.h> + +#include "../NetworkLink.h" +#include "../NetworkComparators.h" +#include "../NetworkErrors.h" +#include "../NetworkItems.h" + +#include "LitResUtil.h" +#include "LitResBooksFeedParser.h" +#include "LitResBooksFeedItem.h" + +#include "LitResByGenresItem.h" + +static const std::string EMPTY_STRING = std::string(); + +LitResByGenresItem::LitResByGenresItem( + const std::vector<shared_ptr<LitResGenre> > &genreTree, + const NetworkLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility, + int flags +) : NetworkCatalogItem( + link, + title, + summary, + urlByType, + accessibility, + flags +), myGenreTree(genreTree) { +} + +std::string LitResByGenresItem::loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener) { + for (std::size_t i = 0; i < myGenreTree.size(); ++i) { + shared_ptr<LitResGenre> genre = myGenreTree.at(i); + if (genre->Children.empty()) { + UrlInfoCollection urlByType = URLByType; + urlByType[NetworkItem::URL_CATALOG] = LitResUtil::generateBooksByGenreUrl(genre->Id); + //TODO add icon change for one genre here + //urlByType[NetworkItem::URL_COVER] = + children.push_back(new LitResBooksFeedItem(true, Link, genre->Title, EMPTY_STRING, urlByType, ALWAYS)); + } else { + children.push_back(new LitResByGenresItem(genre->Children, Link, genre->Title, EMPTY_STRING, URLByType, ALWAYS, FLAG_NONE)); + } + } + listener->finished(); + return std::string(); +} + diff --git a/fbreader/src/network/litres/LitResByGenresItem.h b/fbreader/src/network/litres/LitResByGenresItem.h new file mode 100644 index 0000000..3af0e23 --- /dev/null +++ b/fbreader/src/network/litres/LitResByGenresItem.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __LITRESBYGENRESITEM_H__ +#define __LITRESBYGENRESITEM_H__ + +#include "../NetworkItems.h" + +#include "LitResGenre.h" + +class LitResByGenresItem : public NetworkCatalogItem { + +public: + LitResByGenresItem( + const std::vector<shared_ptr<LitResGenre> > &genreTree, + const NetworkLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility, + int flags + ); + +private: + std::string loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener); + +private: + const std::vector<shared_ptr<LitResGenre> > &myGenreTree; +}; + +#endif /* __LITRESBYGENRESITEM_H__ */ diff --git a/fbreader/src/network/litres/LitResGenre.cpp b/fbreader/src/network/litres/LitResGenre.cpp new file mode 100644 index 0000000..a541948 --- /dev/null +++ b/fbreader/src/network/litres/LitResGenre.cpp @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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 <cstdlib> + +#include <ZLStringUtil.h> +#include <ZLUnicodeUtil.h> +#include <ZLNetworkManager.h> + +#include <ZLibrary.h> +#include <ZLDir.h> +#include <ZLFile.h> +#include <ZLTime.h> + +#include "LitResGenresParser.h" +#include "LitResGenre.h" +#include "LitResUtil.h" + +static const std::string GENRES_CACHE_PREFIX = "litres_genres_"; +static const std::string GENRES_CACHE_SUFFIX = ".xml"; + +LitResGenre::LitResGenre() { +} + +LitResGenre::LitResGenre(const std::string &id, const std::string &title) : Id(id), Title(title) { +} + +LitResGenreMap *LitResGenreMap::ourInstance = 0; + +const LitResGenreMap &LitResGenreMap::Instance() { + if (ourInstance == 0) { + ourInstance = new LitResGenreMap(); + } + return *ourInstance; +} + +LitResGenreMap::LitResGenreMap() : myInitialized(false) { +} + +void LitResGenreMap::validateGenres() const { + if (!myInitialized) { + if (loadGenres()) { + buildGenresTitles(myGenresTree); + myInitialized = true; + } + } +} + +const std::map<std::string, shared_ptr<LitResGenre> > &LitResGenreMap::genresMap() const { + validateGenres(); + return myGenresMap; +} + +const std::vector<shared_ptr<LitResGenre> > &LitResGenreMap::genresTree() const { + validateGenres(); + return myGenresTree; +} + +const std::map<shared_ptr<LitResGenre>, std::string> &LitResGenreMap::genresTitles() const { + validateGenres(); + return myGenresTitles; +} + +void LitResGenreMap::fillGenreIds(const std::string &tag, std::vector<std::string> &ids) const { + std::vector<std::string> words; + int index = 0; + + const std::map<shared_ptr<LitResGenre>, std::string> map = genresTitles(); + + do { + int index2 = tag.find(' ', index); + std::string word = tag.substr(index, index2 - index); + ZLUnicodeUtil::utf8Trim(word); + if (!word.empty()) { + words.push_back(ZLUnicodeUtil::toLower(word)); + } + index = index2 + 1; + } while (index != 0); + + for (std::map<shared_ptr<LitResGenre>, std::string>::const_iterator it = map.begin(); it != map.end(); ++it) { + const LitResGenre &genre = *it->first; + std::string title = ZLUnicodeUtil::toLower(it->second); + bool containsAll = true; + for (std::vector<std::string>::const_iterator jt = words.begin(); jt != words.end(); ++jt) { + if (title.find(*jt) == std::string::npos) { + containsAll = false; + break; + } + } + if (containsAll) { + ids.push_back(genre.Id); + } + } +} + +bool LitResGenreMap::loadGenres() const { + static const std::string directoryPath = ZLNetworkManager::CacheDirectory(); + static shared_ptr<ZLDir> dir = ZLFile(directoryPath).directory(true); + + const std::string url = LitResUtil::url("pages/catalit_genres/"); + + myGenresTree.clear(); + myGenresMap.clear(); + myGenresTitles.clear(); + + if (dir.isNull()) { + shared_ptr<ZLNetworkRequest> networkData = ZLNetworkManager::Instance().createXMLParserRequest( + url, + new LitResGenresParser(myGenresTree, myGenresMap) + ); + const std::string error = ZLNetworkManager::Instance().perform(networkData); + if (!error.empty()) { + myGenresTree.clear(); + myGenresMap.clear(); + myGenresTitles.clear(); + return false; + } + return true; + } + + std::string cacheName; + bool cacheValid = false; + + std::vector<std::string> files; + dir->collectFiles(files, false); + for (std::vector<std::string>::const_iterator it = files.begin(); it != files.end(); ++it) { + const std::string &name = *it; + if (ZLStringUtil::stringStartsWith(name, GENRES_CACHE_PREFIX)) { + cacheName = name; + } + } + files.clear(); + + ZLTime now; + + if (!cacheName.empty()) { + std::string cacheDate = cacheName.substr(GENRES_CACHE_PREFIX.size(), 8); + int cacheYear = std::atoi(cacheDate.substr(0, 4).c_str()); + int cacheMonth = std::atoi(cacheDate.substr(4, 2).c_str()); + int cacheDay = std::atoi(cacheDate.substr(6, 2).c_str()); + int daysDiff = (now.year() - cacheYear) * 365 + (now.month() - cacheMonth) * 31 + (now.dayOfMonth() - cacheDay); + if (daysDiff < 30) { + cacheValid = true; + } + cacheName = dir->itemPath(cacheName); + } + + if (!cacheValid) { + std::string yearStr, monthStr, dayStr; + ZLStringUtil::appendNumber(yearStr, now.year()); + ZLStringUtil::appendNumber(monthStr, now.month()); + ZLStringUtil::appendNumber(dayStr, now.dayOfMonth()); + while (monthStr.size() < 2) { + monthStr = "0" + monthStr; + } + while (dayStr.size() < 2) { + dayStr = "0" + dayStr; + } + + const std::string fileName = dir->path() + ZLibrary::FileNameDelimiter + + GENRES_CACHE_PREFIX + yearStr + monthStr + dayStr + GENRES_CACHE_SUFFIX; + + const std::string error = ZLNetworkManager::Instance().downloadFile(url, fileName); + if (!error.empty()) { + ZLFile(fileName).remove(); + } else { + ZLFile(cacheName).remove(); + cacheName = fileName; + } + } + + if (cacheName.empty()) { + return false; + } + + shared_ptr<ZLXMLReader> parser = new LitResGenresParser(myGenresTree, myGenresMap); + return parser->readDocument(ZLFile(cacheName)); +} + +void LitResGenreMap::buildGenresTitles(const std::vector<shared_ptr<LitResGenre> > &genres, const std::string &titlePrefix) const { + for (std::vector<shared_ptr<LitResGenre> >::const_iterator it = genres.begin(); it != genres.end(); ++it) { + shared_ptr<LitResGenre> genre = *it; + std::string title = titlePrefix.empty() ? (genre->Title) : (titlePrefix + "/" + genre->Title); + if (genre->Id.empty()) { + buildGenresTitles(genre->Children, title); + } else { + myGenresTitles[genre] = title; + } + } +} diff --git a/fbreader/src/network/litres/LitResGenre.h b/fbreader/src/network/litres/LitResGenre.h new file mode 100644 index 0000000..4b2bd3b --- /dev/null +++ b/fbreader/src/network/litres/LitResGenre.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __LITRESGENRE_H__ +#define __LITRESGENRE_H__ + +#include <string> +#include <vector> +#include <map> + +#include <shared_ptr.h> + +struct LitResGenre { + std::string Id; + std::string Title; + std::vector<shared_ptr<LitResGenre> > Children; + + LitResGenre(); + LitResGenre(const std::string &id, const std::string &title); +}; + +class LitResGenreMap { + +public: + static const LitResGenreMap &Instance(); + +private: + static LitResGenreMap *ourInstance; + +private: + LitResGenreMap(); + +public: + const std::map<std::string, shared_ptr<LitResGenre> > &genresMap() const; + const std::vector<shared_ptr<LitResGenre> > &genresTree() const; + const std::map<shared_ptr<LitResGenre>, std::string> &genresTitles() const; + void fillGenreIds(const std::string &tag, std::vector<std::string> &ids) const; + +private: + void validateGenres() const; + bool loadGenres() const; + void buildGenresTitles(const std::vector<shared_ptr<LitResGenre> > &genres, const std::string &titlePrefix = "") const; + + mutable std::vector<shared_ptr<LitResGenre> > myGenresTree; + mutable std::map<std::string, shared_ptr<LitResGenre> > myGenresMap; + mutable std::map<shared_ptr<LitResGenre>, std::string> myGenresTitles; + mutable bool myInitialized; +}; + +#endif /* __LITRESGENRE_H__ */ diff --git a/fbreader/src/network/litres/LitResGenresParser.cpp b/fbreader/src/network/litres/LitResGenresParser.cpp new file mode 100644 index 0000000..9ed3f2d --- /dev/null +++ b/fbreader/src/network/litres/LitResGenresParser.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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 <ZLStringUtil.h> + +#include "LitResGenresParser.h" + +#include "LitResGenre.h" + +static const std::string TAG_GENRE = "genre"; + + +LitResGenresParser::LitResGenresParser(std::vector<shared_ptr<LitResGenre> > &genresTree, std::map<std::string, shared_ptr<LitResGenre> > &genresMap) : + myGenresTree(genresTree), + myGenresMap(genresMap), + myDontPopStack(false) { +} + +void LitResGenresParser::saveGenre(shared_ptr<LitResGenre> genre, const std::string &token) { + if (myStack.empty()) { + myGenresTree.push_back(genre); + } else { + myStack.back()->Children.push_back(genre); + } + if (genre->Id.empty()) { + myStack.push_back(genre); + } else { + myDontPopStack = true; + if (!token.empty()) { + myGenresMap[token] = genre; + } + } +} + +void LitResGenresParser::startElementHandler(const char *tag, const char **attributes) { + if (TAG_GENRE == tag) { + const char *id = attributeValue(attributes, "id"); + const char *title = attributeValue(attributes, "title"); + const char *token = attributeValue(attributes, "token"); + std::string strId, strTitle, strToken; + if (id != 0) { + strId = id; + } + if (title != 0) { + strTitle = title; + } + if (token != 0) { + strToken = token; + } + saveGenre(new LitResGenre(strId, strTitle), strToken); + } +} + +void LitResGenresParser::endElementHandler(const char *tag) { + if (TAG_GENRE == tag) { + if (!myDontPopStack) { + myStack.pop_back(); + } + myDontPopStack = false; + } +} + +void LitResGenresParser::characterDataHandler(const char *, std::size_t) { +} + diff --git a/fbreader/src/network/litres/LitResGenresParser.h b/fbreader/src/network/litres/LitResGenresParser.h new file mode 100644 index 0000000..424d37b --- /dev/null +++ b/fbreader/src/network/litres/LitResGenresParser.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __LITRESGENRESPARSER_H__ +#define __LITRESGENRESPARSER_H__ + + +#include <map> +#include <vector> +#include <string> + +#include <ZLXMLReader.h> + +struct LitResGenre; + +class LitResGenresParser : public ZLXMLReader { + +public: + LitResGenresParser(std::vector<shared_ptr<LitResGenre> > &genresTree, std::map<std::string, shared_ptr<LitResGenre> > &genresMap); + +private: + void startElementHandler(const char *tag, const char **attributes); + void endElementHandler(const char *tag); + void characterDataHandler(const char *text, std::size_t len); + + void saveGenre(shared_ptr<LitResGenre> genre, const std::string &token); + + const std::string &titlePrefix(); + +private: + std::vector<shared_ptr<LitResGenre> > &myGenresTree; + std::map<std::string, shared_ptr<LitResGenre> > &myGenresMap; + std::vector<shared_ptr<LitResGenre> > myStack; + bool myDontPopStack; + + std::vector<std::string> myTitleStack; + std::string myTitlePrefix; +}; + +#endif /* __LITRESGENRESPARSER_H__ */ diff --git a/fbreader/src/network/litres/LitResRecommendationsItem.cpp b/fbreader/src/network/litres/LitResRecommendationsItem.cpp new file mode 100644 index 0000000..54d7cd7 --- /dev/null +++ b/fbreader/src/network/litres/LitResRecommendationsItem.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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 <ZLStringUtil.h> +#include <ZLNetworkUtil.h> + +#include "../NetworkLink.h" +#include "../authentication/litres/LitResAuthenticationManager.h" + +#include "LitResRecommendationsItem.h" + +LitResRecommendationsItem::LitResRecommendationsItem( + const OPDSLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility +) : OPDSCatalogItem( + link, + title, + summary, + urlByType, + accessibility +) { } + +std::string LitResRecommendationsItem::getCatalogUrl() { + LitResAuthenticationManager &mgr = (LitResAuthenticationManager&)*Link.authenticationManager(); + std::string catalogUrl = OPDSCatalogItem::getCatalogUrl(); + if (mgr.isAuthorised().Status == B3_FALSE) { + return catalogUrl; + } + std::string query = ZLStringUtil::join(mgr.getPurchasedIds(), ","); + ZLNetworkUtil::appendParameter(catalogUrl, "ids", query); + return catalogUrl; +} diff --git a/fbreader/src/network/litres/LitResRecommendationsItem.h b/fbreader/src/network/litres/LitResRecommendationsItem.h new file mode 100644 index 0000000..ba27623 --- /dev/null +++ b/fbreader/src/network/litres/LitResRecommendationsItem.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __LITRESRECOMMENDATIONSITEM_H__ +#define __LITRESRECOMMENDATIONSITEM_H__ + +#include "../opds/OPDSCatalogItem.h" + +class LitResRecommendationsItem : public OPDSCatalogItem { + +public: + LitResRecommendationsItem( + const OPDSLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility = ALWAYS + ); + +private: + std::string getCatalogUrl(); +}; + +#endif /* __LITRESRECOMMENDATIONSITEM_H__ */ diff --git a/fbreader/src/network/litres/LitResUtil.cpp b/fbreader/src/network/litres/LitResUtil.cpp new file mode 100644 index 0000000..992b7d9 --- /dev/null +++ b/fbreader/src/network/litres/LitResUtil.cpp @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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 <ZLStringUtil.h> + +#include "../NetworkLink.h" +#include "../opds/OPDSMetadata.h" + +#include "LitResBookshelfItem.h" +#include "LitResBooksFeedItem.h" +#include "LitResRecommendationsItem.h" +#include "LitResByGenresItem.h" +#include "LitResAuthorsItem.h" + +#include "LitResUtil.h" + + +static std::string LITRES_API_URL = "://robot.litres.ru/"; + +std::string LitResUtil::url(const std::string &path) { + std::string url = LITRES_API_URL + path; + if (ZLNetworkUtil::hasParameter(url, "sid") || + ZLNetworkUtil::hasParameter(url, "pwd")) { + url = "https" + url; + } else { + url = "http" + url; + } + return url; +} + +std::string LitResUtil::url(const NetworkLink &link, const std::string &path) { + std::string urlString = url(path); + link.rewriteUrl(urlString); + return urlString; +} + +std::string LitResUtil::url(bool secure, const std::string &path) { + std::string url = LITRES_API_URL + path; + if (secure) { + url = "https" + url; + } else { + url = "http" + url; + } + return url; +} + +std::string LitResUtil::url(const NetworkLink &link, bool secure, const std::string &path) { + std::string urlString = url(secure, path); + link.rewriteUrl(urlString, true); + return urlString; +} + +std::string LitResUtil::generateTrialUrl(std::string bookId) { + std::size_t len = bookId.length(); + if (len < 8) { + bookId = std::string(8 - len, '0') + bookId; + } + std::string query = "static/trials/%s/%s/%s/%s.fb2.zip"; + query = ZLStringUtil::printf(query, bookId.substr(0,2)); + query = ZLStringUtil::printf(query, bookId.substr(2,2)); + query = ZLStringUtil::printf(query, bookId.substr(4,2)); + query = ZLStringUtil::printf(query, bookId); + return url(false, query); +} + +std::string LitResUtil::generatePurchaseUrl(const NetworkLink &link, const std::string &bookId) { + std::string query; + ZLNetworkUtil::appendParameter(query, "art", bookId); + return url(link, true, "pages/purchase_book/" + query); +} + +std::string LitResUtil::generateDownloadUrl(const std::string &bookId) { + std::string query; + ZLNetworkUtil::appendParameter(query, "art", bookId); + return url(true, "pages/catalit_download_book/" + query); +} + +std::string LitResUtil::generateAlsoReadUrl(const std::string &bookId) { + std::string query; + ZLNetworkUtil::appendParameter(query, "rating", "with"); + ZLNetworkUtil::appendParameter(query, "art", bookId); + return url(false, "pages/catalit_browser/" + query); +} + +std::string LitResUtil::generateBooksByGenreUrl(const std::string &genreId) { + std::string query; + ZLNetworkUtil::appendParameter(query, "checkpoint", "2000-01-01"); + ZLNetworkUtil::appendParameter(query, "genre", genreId); + return url(false, "pages/catalit_browser/" + query); +} + +std::string LitResUtil::generateBooksByAuthorUrl(const std::string &authorId) { + std::string query; + ZLNetworkUtil::appendParameter(query, "checkpoint", "2000-01-01"); + ZLNetworkUtil::appendParameter(query, "person", authorId); + return url(false, "pages/catalit_browser/" + query); +} + +shared_ptr<NetworkItem> LitResUtil::createLitResNode(shared_ptr<ZLMimeType> type, std::string rel, const NetworkLink &link, std::string title, + std::string annotation, std::map<NetworkItem::URLType,std::string> urlMap, bool dependsOnAccount) { + static const std::string TYPE = "type"; + static const std::string NO = "no"; + + std::string litresType = type->getParameter(TYPE); + + if (rel == OPDSConstants::REL_BOOKSHELF) { + return new LitResBookshelfItem( + link, + title, + annotation, + urlMap, + NetworkCatalogItem::SIGNED_IN + ); + } else if (rel == OPDSConstants::REL_RECOMMENDATIONS) { + return new LitResRecommendationsItem( + (OPDSLink&)link, + title, + annotation, + urlMap, + NetworkCatalogItem::HAS_BOOKS + ); + } else if (litresType == ZLMimeType::APPLICATION_LITRES_XML_BOOKS->getParameter(TYPE)) { + int flags = NetworkCatalogItem::FLAGS_DEFAULT; + if (type->getParameter("groupSeries") == NO) { + flags &= ~NetworkCatalogItem::FLAG_GROUP_MORE_THAN_1_BOOK_BY_SERIES; + } + if (type->getParameter("showAuthor") == "false") { + flags &= ~NetworkCatalogItem::FLAG_SHOW_AUTHOR; + } + bool sort = type->getParameter("sort") != NO; + return new LitResBooksFeedItem( + sort, + link, + title, + annotation, + urlMap, + dependsOnAccount ? NetworkCatalogItem::SIGNED_IN : NetworkCatalogItem::ALWAYS, + flags + ); + } else if (litresType == ZLMimeType::APPLICATION_LITRES_XML_GENRES->getParameter(TYPE)) { + return new LitResByGenresItem( + LitResGenreMap::Instance().genresTree(), + link, + title, + annotation, + urlMap, + NetworkCatalogItem::ALWAYS, + NetworkCatalogItem::FLAG_SHOW_AUTHOR + ); + } else if (litresType == ZLMimeType::APPLICATION_LITRES_XML_AUTHORS->getParameter(TYPE)) { + return new LitResAuthorsItem( + link, + title, + annotation, + urlMap, + NetworkCatalogItem::ALWAYS + ); + } else { + return 0; + } +} diff --git a/fbreader/src/network/litres/LitResUtil.h b/fbreader/src/network/litres/LitResUtil.h new file mode 100644 index 0000000..fd23a08 --- /dev/null +++ b/fbreader/src/network/litres/LitResUtil.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __LITRESUTIL_H__ +#define __LITRESUTIL_H__ + +#include <string> + +#include "../NetworkItems.h" + +class NetworkLink; + +class LitResUtil { + +public: + static std::string url(const std::string &path); + static std::string url(const NetworkLink &link, const std::string &path); + static std::string url(const NetworkLink &link, bool secure, const std::string &path); + static std::string url(bool secure, const std::string &path); + + static std::string generateTrialUrl(std::string bookId); + static std::string generatePurchaseUrl(const NetworkLink &link, const std::string &bookId); + static std::string generateDownloadUrl(const std::string &bookId); + static std::string generateAlsoReadUrl(const std::string &bookId); + static std::string generateBooksByGenreUrl(const std::string &genreId); + static std::string generateBooksByAuthorUrl(const std::string &authorId); + +public: + static shared_ptr<NetworkItem> createLitResNode(shared_ptr<ZLMimeType> type, std::string rel, + const NetworkLink &link, std::string title, + std::string annotation, std::map<NetworkItem::URLType,std::string> urlMap, + bool dependsOnAccount); + +private: + LitResUtil(); +}; + +#endif /* __LITRESUTIL_H__ */ diff --git a/fbreader/src/network/litres/SortedCatalogItem.cpp b/fbreader/src/network/litres/SortedCatalogItem.cpp new file mode 100644 index 0000000..79d7f49 --- /dev/null +++ b/fbreader/src/network/litres/SortedCatalogItem.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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 "SortedCatalogItem.h" + +bool SortedCatalogItem::BookItemFilter::accepts(NetworkItem* item) const { + return zlobject_cast<NetworkBookItem*>(item) != 0; +} + +bool SortedCatalogItem::BySeriesFilter::accepts(NetworkItem* item) const { + NetworkBookItem* bookItem = zlobject_cast<NetworkBookItem*>(item); + return bookItem != 0 && !bookItem->SeriesTitle.empty(); +} + +SortedCatalogItem::SortedCatalogItem(const NetworkCatalogItem &parent, const ZLResource &resource, + const NetworkItem::List &children, int flags) + : NetworkCatalogItem(parent.Link, resource.value(), resource["summary"].value(), parent.URLByType, ALWAYS, flags) { + myChildren = children; +} + +std::string SortedCatalogItem::loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener) { + children.assign(myChildren.begin(), myChildren.end()); + listener->finished(); + return std::string(); +} + +bool SortedCatalogItem::isEmpty() const { + return myChildren.empty(); +} + +const ZLResource &SortedCatalogItem::resource(const std::string &resourceKey) { + return ZLResource::resource("networkView")[resourceKey]; +} diff --git a/fbreader/src/network/litres/SortedCatalogItem.h b/fbreader/src/network/litres/SortedCatalogItem.h new file mode 100644 index 0000000..e4f2744 --- /dev/null +++ b/fbreader/src/network/litres/SortedCatalogItem.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __SORTEDCATALOGITEM_H__ +#define __SORTEDCATALOGITEM_H__ + +#include <algorithm> + +#include <ZLResource.h> + +#include "../NetworkComparators.h" +#include "../NetworkItems.h" + +class SortedCatalogItem : public NetworkCatalogItem { + +public: + class BookItemFilter { + public: + bool accepts(NetworkItem* item) const; + }; + + class BySeriesFilter { + public: + bool accepts(NetworkItem* item) const; + }; + + //TODO maybe refactor (using templates is too complex for this simple case + //(templates were used because in C++ virtual methods can't be called from constructor) + template <class T, class F> + static SortedCatalogItem* create(const NetworkCatalogItem &parent, const std::string &resourceKey, + const NetworkItem::List &children, int flags, T comparator, F filter); + template <class T> + static SortedCatalogItem* create(const NetworkCatalogItem &parent, const std::string &resourceKey, + const NetworkItem::List &children, int flags, T comparator); + static SortedCatalogItem* create(const NetworkCatalogItem &parent, const std::string &resourceKey, + const NetworkItem::List &children, int flags); + +public: + SortedCatalogItem(const NetworkCatalogItem &parent, const ZLResource &resource, const NetworkItem::List &children, int flags); + +public: + std::string loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener); + bool isEmpty() const; + //TODO following method should be in class NetworkLibrary or smth like that + static const ZLResource &resource(const std::string &resourceKey); + +protected: + NetworkItem::List myChildren; +}; + +template <class T, class F> +SortedCatalogItem* SortedCatalogItem::create(const NetworkCatalogItem &parent, const std::string &resourceKey, + const NetworkItem::List &children, int flags, T comparator, F filter) { + NetworkItem::List tmpChildren; + for (std::size_t i = 0; i < children.size(); ++i) { + shared_ptr<NetworkItem> child = children.at(i); + if (filter.accepts(&(*child))) { + tmpChildren.push_back(child); + } + } + std::sort(tmpChildren.begin(), tmpChildren.end(), comparator); + return new SortedCatalogItem(parent, resource(resourceKey), tmpChildren, flags); +} + +template <class T> +SortedCatalogItem* SortedCatalogItem::create(const NetworkCatalogItem &parent, const std::string &resourceKey, + const NetworkItem::List &children, int flags, T comparator) { + return create(parent, resourceKey, children, flags, comparator, BookItemFilter()); +} + +inline SortedCatalogItem* SortedCatalogItem::create(const NetworkCatalogItem &parent, const std::string &resourceKey, + const NetworkItem::List &children, int flags) { + BookItemFilter filter; + NetworkItem::List tmpChildren; + for (std::size_t i = 0; i < children.size(); ++i) { + shared_ptr<NetworkItem> child = children.at(i); + if (filter.accepts(&(*child))) { + tmpChildren.push_back(child); + } + } + return new SortedCatalogItem(parent, resource(resourceKey), tmpChildren, flags); +} + +#endif /* __SORTEDCATALOGITEM_H__ */ diff --git a/fbreader/src/network/opds/NetworkOPDSFeedReader.cpp b/fbreader/src/network/opds/NetworkOPDSFeedReader.cpp new file mode 100644 index 0000000..3c1ad0a --- /dev/null +++ b/fbreader/src/network/opds/NetworkOPDSFeedReader.cpp @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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 <algorithm> + +#include <ZLStringUtil.h> +#include <ZLUnicodeUtil.h> +#include <ZLNetworkUtil.h> +#include <ZLMimeType.h> + +#include "NetworkOPDSFeedReader.h" +#include "OPDSCatalogItem.h" +#include "OPDSXMLParser.h" + +#include "../NetworkOperationData.h" +#include "../NetworkItems.h" +#include "../BookReference.h" +#include "OPDSBookItem.h" + +#include "../litres/LitResUtil.h" + + +NetworkOPDSFeedReader::NetworkOPDSFeedReader( + const OPDSLink &link, + const std::string &baseURL, + NetworkOperationData &result +) : + myLink(link), + myBaseURL(baseURL), + myData(result), + myIndex(0), + myOpenSearchStartIndex(0) { +} + +void NetworkOPDSFeedReader::processFeedStart() { +} + +void NetworkOPDSFeedReader::processFeedMetadata(shared_ptr<OPDSFeedMetadata> feed) { + for (std::size_t i = 0; i < feed->links().size(); ++i) { + ATOMLink &link = *(feed->links()[i]); + const std::string &href = ZLNetworkUtil::url(myBaseURL, link.href()); + shared_ptr<ZLMimeType> type = ZLMimeType::get(link.type()); + const std::string &rel = myLink.relation(link.rel(), link.type()); + if (type->weakEquals(*ZLMimeType::APPLICATION_ATOM_XML)) { + if (rel == "self") { + } else if (rel == "next") { + myData.ResumeURI = href; + } + } + } + myOpenSearchStartIndex = feed->getOpensearchStartIndex() - 1; +} + + +void NetworkOPDSFeedReader::processFeedEnd() { + for (std::size_t i = 0; i < myData.Items.size(); ++i) { + NetworkItem &item = *myData.Items[i]; + if (!item.isInstanceOf(NetworkBookItem::TYPE_ID)) { + continue; + } + NetworkBookItem &book = (NetworkBookItem&) item; + book.Index += myOpenSearchStartIndex; + } +} + +void NetworkOPDSFeedReader::processFeedEntry(shared_ptr<OPDSEntry> entry) { + if (entry.isNull()) { + return; + } + + std::map<std::string,OPDSLink::FeedCondition>::const_iterator it = myLink.myFeedConditions.find(entry->id()->uri()); + if (it != myLink.myFeedConditions.end() && it->second == OPDSLink::CONDITION_NEVER) { + return; + } + OPDSEntry &e = *entry; + bool hasBookLink = false; + for (std::size_t i = 0; i < e.links().size(); ++i) { + ATOMLink &link = *(e.links()[i]); + const std::string &type = link.type(); + const std::string &rel = myLink.relation(link.rel(), type); + if (rel == OPDSConstants::REL_ACQUISITION || + rel == OPDSConstants::REL_ACQUISITION_OPEN || + rel == OPDSConstants::REL_ACQUISITION_SAMPLE || + rel == OPDSConstants::REL_ACQUISITION_BUY || + rel == OPDSConstants::REL_ACQUISITION_CONDITIONAL || + rel == OPDSConstants::REL_ACQUISITION_SAMPLE_OR_FULL || + (rel.empty() && OPDSBookItem::formatByZLMimeType(type) != BookReference::NONE)) { + hasBookLink = true; + break; + } + } + + shared_ptr<NetworkItem> item; + if (hasBookLink) { + item = new OPDSBookItem(myLink, e, myBaseURL, myIndex++); + } else { + item = readCatalogItem(e); + } + if (!item.isNull()) { + myData.Items.push_back(item); + } +} + +shared_ptr<NetworkItem> NetworkOPDSFeedReader::readCatalogItem(OPDSEntry &entry) { + std::string coverURL; + std::string url; + bool urlIsAlternate = false; + std::string htmlURL; + std::string litresRel; + shared_ptr<ZLMimeType> litresMimeType; + int catalogFlags = NetworkCatalogItem::FLAGS_DEFAULT; + for (std::size_t i = 0; i < entry.links().size(); ++i) { + ATOMLink &link = *(entry.links()[i]); + const std::string &href = ZLNetworkUtil::url(myBaseURL, link.href()); + shared_ptr<ZLMimeType> type = ZLMimeType::get(link.type()); + const std::string &rel = myLink.relation(link.rel(), link.type()); + if (ZLMimeType::isImage(type)) { + if (rel == OPDSConstants::REL_THUMBNAIL || rel == OPDSConstants::REL_IMAGE_THUMBNAIL) { + coverURL = href; + } else if (coverURL.empty() && (rel == OPDSConstants::REL_COVER || ZLStringUtil::stringStartsWith(rel, OPDSConstants::REL_IMAGE_PREFIX))) { + coverURL = href; + } + } else if (type->weakEquals(*ZLMimeType::APPLICATION_ATOM_XML)) { + if (rel == ATOMConstants::REL_ALTERNATE) { + if (url.empty()) { + url = href; + urlIsAlternate = true; + } + } else { + url = href; + urlIsAlternate = false; + if (rel == OPDSConstants::REL_CATALOG_AUTHOR) { + catalogFlags &= !NetworkCatalogItem::FLAG_SHOW_AUTHOR; + } + } + } else if (type->weakEquals(*ZLMimeType::TEXT_HTML)) { + if (rel == OPDSConstants::REL_ACQUISITION || + rel == ATOMConstants::REL_ALTERNATE || + rel.empty()) { + htmlURL = href; + } + } else if (type->weakEquals(*ZLMimeType::APPLICATION_LITRES_XML)) { + url = href; + litresRel = rel; + litresMimeType = type; + } + } + + if (url.empty() && htmlURL.empty()) { + return 0; + } + + if (!url.empty() && !urlIsAlternate) { + htmlURL.erase(); + } + + std::map<std::string,OPDSLink::FeedCondition>::const_iterator it = + myLink.myFeedConditions.find(entry.id()->uri()); + bool dependsOnAccount = + it != myLink.myFeedConditions.end() && + it->second == OPDSLink::CONDITION_SIGNED_IN; + + std::string annotation = entry.summary(); + annotation.erase(std::remove(annotation.begin(), annotation.end(), 0x09), annotation.end()); + annotation.erase(std::remove(annotation.begin(), annotation.end(), 0x0A), annotation.end()); + NetworkItem::UrlInfoCollection urlMap; + urlMap[NetworkItem::URL_COVER] = coverURL; + urlMap[NetworkItem::URL_CATALOG] = url; + urlMap[NetworkItem::URL_HTML_PAGE] = htmlURL; + + if (!litresMimeType.isNull()) { + return LitResUtil::createLitResNode(litresMimeType, litresRel, myData.Link, entry.title(), annotation, urlMap, dependsOnAccount); + } + return new OPDSCatalogItem( + (OPDSLink&)myData.Link, + entry.title(), + annotation, + urlMap, + dependsOnAccount ? NetworkCatalogItem::SIGNED_IN : NetworkCatalogItem::ALWAYS, + catalogFlags + ); +} diff --git a/fbreader/src/network/opds/NetworkOPDSFeedReader.h b/fbreader/src/network/opds/NetworkOPDSFeedReader.h new file mode 100644 index 0000000..f51b1bf --- /dev/null +++ b/fbreader/src/network/opds/NetworkOPDSFeedReader.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __NETWORKOPDSFEEDREADER_H__ +#define __NETWORKOPDSFEEDREADER_H__ + +#include <map> +#include <string> + +#include "OPDSFeedReader.h" +#include "OPDSLink.h" + +class NetworkOperationData; + +class NetworkItem; + +class NetworkOPDSFeedReader : public OPDSFeedReader { + +public: + NetworkOPDSFeedReader( + const OPDSLink &link, + const std::string &baseURL, + NetworkOperationData &result + ); + +public: + void processFeedEntry(shared_ptr<OPDSEntry> entry); + void processFeedStart(); + void processFeedMetadata(shared_ptr<OPDSFeedMetadata> feed); + void processFeedEnd(); + +private: + shared_ptr<NetworkItem> readCatalogItem(OPDSEntry &entry); + +private: + const OPDSLink &myLink; + const std::string myBaseURL; + NetworkOperationData &myData; + unsigned int myIndex; + unsigned int myOpenSearchStartIndex; +}; + + +#endif /* __NETWORKOPDSFEEDREADER_H__ */ diff --git a/fbreader/src/network/opds/OPDSBookItem.cpp b/fbreader/src/network/opds/OPDSBookItem.cpp new file mode 100644 index 0000000..6899afa --- /dev/null +++ b/fbreader/src/network/opds/OPDSBookItem.cpp @@ -0,0 +1,310 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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 <ZLNetworkManager.h> +#include <ZLNetworkUtil.h> +#include <ZLUnicodeUtil.h> +#include <ZLStringUtil.h> + +#include "../NetworkLink.h" +#include "OPDSXMLParser.h" + +#include "OPDSBookItem.h" +#include "OPDSCatalogItem.h" + +#include "../tree/NetworkTreeFactory.h" + +OPDSBookItem::OPDSBookItem(const OPDSLink &link, OPDSEntry &entry, std::string baseUrl, unsigned int index) : + NetworkBookItem( + link, + entry.id()->uri(), + index, + entry.title(), + getAnnotation(entry), + entry.dcLanguage(), + getDate(entry), + getAuthors(entry), + getTags(entry), + entry.seriesTitle(), + entry.seriesIndex(), + getUrls(link, entry, baseUrl), + getReferences(link, entry, baseUrl) + ) { + myRelatedInfos = getRelatedUrls(link, entry, baseUrl); + myInformationIsFull = false; +} + +bool OPDSBookItem::isFullyLoaded() const { + return myInformationIsFull || URLByType.find(URL_SINGLE_ENTRY) == URLByType.end(); +} + +class OPDSBookItemFullInfoLoader : public ZLNetworkRequest::Listener { +public: + OPDSBookItemFullInfoLoader(OPDSBookItem &item, shared_ptr<ZLNetworkRequest> request, shared_ptr<ZLNetworkRequest::Listener> listener) : + myItem(item), myListener(listener) { + request->setListener(this); + ZLNetworkManager::Instance().performAsync(request); + } + + void finished(const std::string &error) { + if (error.empty()) { + myItem.myInformationIsFull = true; + } + myListener->finished(error); + } +private: + OPDSBookItem &myItem; + shared_ptr<ZLNetworkRequest::Listener> myListener; +}; + +void OPDSBookItem::loadFullInformation(shared_ptr<ZLNetworkRequest::Listener> listener) { + if (myInformationIsFull) { + listener->finished(); + return; + } + + if (URLByType.find(URL_SINGLE_ENTRY) == URLByType.end()) { + myInformationIsFull = true; + listener->finished(); + return; + } + + std::string url = URLByType[URL_SINGLE_ENTRY]; + shared_ptr<ZLNetworkRequest> request = ZLNetworkManager::Instance().createXMLParserRequest( + url, new OPDSXMLParser(new FullEntryReader(*this, (const OPDSLink&)Link, url), true) + ); + + new OPDSBookItemFullInfoLoader(*this, request, listener); +} + +std::vector<shared_ptr<NetworkItem> > OPDSBookItem::getRelatedCatalogsItems() const { + std::vector<shared_ptr<NetworkItem> > items; + for (std::size_t i = 0; i < myRelatedInfos.size(); ++i) { + shared_ptr<RelatedUrlInfo> urlInfo = myRelatedInfos.at(i); + if (!urlInfo->MimeType->weakEquals(*ZLMimeType::APPLICATION_ATOM_XML)) { + continue; + //TODO implement items for loading link in browser + } + UrlInfoCollection urlByType = URLByType; + urlByType[URL_CATALOG] = urlInfo->Url; + OPDSCatalogItem *item = new OPDSCatalogItem(static_cast<const OPDSLink&>(Link), urlInfo->Title, std::string(), urlByType); + items.push_back(item); + } + return items; +} + +std::string OPDSBookItem::getAnnotation(OPDSEntry &entry) { + //TODO implement ATOMContent support (and return content) + return entry.summary(); +} + +std::string OPDSBookItem::getDate(OPDSEntry &entry) { + std::string date; + if (!entry.dcIssued().isNull()) { + date = entry.dcIssued()->getDateTime(true); + } + return date; +} + +std::vector<NetworkBookItem::AuthorData> OPDSBookItem::getAuthors(OPDSEntry &entry) { + std::vector<NetworkBookItem::AuthorData> authors; + for (std::size_t i = 0; i < entry.authors().size(); ++i) { + ATOMAuthor &author = *(entry.authors()[i]); + NetworkBookItem::AuthorData authorData; + std::string name = author.name(); + std::string lowerCased = ZLUnicodeUtil::toLower(name); + static const std::string authorPrefix = "author:"; + std::size_t index = lowerCased.find(authorPrefix); + if (index != std::string::npos) { + name = name.substr(index + authorPrefix.size()); + } else { + static const std::string authorsPrefix = "authors:"; + index = lowerCased.find(authorsPrefix); + if (index != std::string::npos) { + name = name.substr(index + authorsPrefix.size()); + } + } + index = name.find(','); + if (index != std::string::npos) { + std::string before = name.substr(0, index); + std::string after = name.substr(index + 1); + ZLUnicodeUtil::utf8Trim(before); + ZLUnicodeUtil::utf8Trim(after); + authorData.SortKey = before; + authorData.DisplayName = after + ' ' + before; + } else { + ZLUnicodeUtil::utf8Trim(name); + index = name.rfind(' '); + authorData.SortKey = name.substr(index + 1); + authorData.DisplayName = name; + } + authors.push_back(authorData); + } + return authors; +} + +std::vector<std::string> OPDSBookItem::getTags(OPDSEntry &entry) { + std::vector<std::string> tags; + for (std::size_t i = 0; i < entry.categories().size(); ++i) { + ATOMCategory &category = *(entry.categories()[i]); + tags.push_back(category.label()); + } + return tags; +} + +NetworkItem::UrlInfoCollection OPDSBookItem::getUrls(const OPDSLink &networkLink, OPDSEntry &entry, std::string baseUrl) { + //TODO split urls and references in UrlInfoCollection, like it's implemented in FBReaderJ + NetworkItem::UrlInfoCollection urlMap; + for (std::size_t i = 0; i < entry.links().size(); ++i) { + ATOMLink &link = *(entry.links()[i]); + const std::string href = ZLNetworkUtil::url(baseUrl, link.href()); + shared_ptr<ZLMimeType> type = ZLMimeType::get(link.type()); + const std::string &rel = networkLink.relation(link.rel(), link.type()); + if (ZLStringUtil::stringStartsWith(rel, OPDSConstants::REL_IMAGE_PREFIX) || rel == OPDSConstants::REL_COVER) { + if (urlMap[NetworkItem::URL_COVER].empty() && ZLMimeType::isImage(type)) { + urlMap[NetworkItem::URL_COVER] = href; + } + } else if (rel == OPDSConstants::REL_THUMBNAIL || rel == OPDSConstants::REL_IMAGE_THUMBNAIL) { + if (ZLMimeType::isImage(type)) { + urlMap[NetworkItem::URL_COVER] = href; + } + } else if (type->weakEquals(*ZLMimeType::APPLICATION_ATOM_XML) && + rel == ATOMConstants::REL_ALTERNATE && + type->getParameter("type") == "entry") { + urlMap[NetworkItem::URL_SINGLE_ENTRY] = href; + } + } + return urlMap; +} + +OPDSBookItem::RelatedUrlsList OPDSBookItem::getRelatedUrls(const OPDSLink &networkLink, OPDSEntry &entry, std::string baseUrl) { + OPDSBookItem::RelatedUrlsList relatedUrlList; + for (std::size_t i = 0; i < entry.links().size(); ++i) { + ATOMLink &link = *(entry.links()[i]); + const std::string href = ZLNetworkUtil::url(baseUrl, link.href()); + shared_ptr<ZLMimeType> type = ZLMimeType::get(link.type()); + const std::string &rel = networkLink.relation(link.rel(), link.type()); + if (rel == ATOMConstants::REL_RELATED) { + relatedUrlList.push_back(new RelatedUrlInfo(link.title(), type, href)); + } + } + return relatedUrlList; +} + +std::vector<shared_ptr<BookReference> > OPDSBookItem::getReferences(const OPDSLink &networkLink, OPDSEntry &entry, std::string baseUrl) { + //TODO split urls and references in UrlInfoCollection, like it's implemented in FBReaderJ + std::vector<shared_ptr<BookReference> > references; + for (std::size_t i = 0; i < entry.links().size(); ++i) { + ATOMLink &link = *(entry.links()[i]); + const std::string href = ZLNetworkUtil::url(baseUrl, link.href()); + shared_ptr<ZLMimeType> type = ZLMimeType::get(link.type()); + const std::string &rel = networkLink.relation(link.rel(), link.type()); + const BookReference::Type referenceType = typeByRelation(rel); + if (referenceType == BookReference::BUY) { + std::string price = BuyBookReference::price( + link.userData(OPDSXMLParser::KEY_PRICE), + link.userData(OPDSXMLParser::KEY_CURRENCY) + ); + if (price.empty()) { + price = BuyBookReference::price( + entry.userData(OPDSXMLParser::KEY_PRICE), + entry.userData(OPDSXMLParser::KEY_CURRENCY) + ); + } + if (type == ZLMimeType::TEXT_HTML) { + references.push_back(new BuyBookReference( + href, BookReference::NONE, BookReference::BUY_IN_BROWSER, price + )); + } else { + BookReference::Format format = formatByZLMimeType(link.userData(OPDSXMLParser::KEY_FORMAT)); + if (format != BookReference::NONE) { + references.push_back(new BuyBookReference( + href, format, BookReference::BUY, price + )); + } + } + } else if (referenceType != BookReference::UNKNOWN) { + BookReference::Format format = formatByZLMimeType(link.type()); + if (format != BookReference::NONE) { + references.push_back(new BookReference(href, format, referenceType)); + } + } + } + return references; +} + +BookReference::Format OPDSBookItem::formatByZLMimeType(const std::string &mimeType) { + shared_ptr<ZLMimeType> type = ZLMimeType::get(mimeType); + if (type == ZLMimeType::APPLICATION_FB2_ZIP) { + return BookReference::FB2_ZIP; + } else if (type == ZLMimeType::APPLICATION_EPUB_ZIP) { + return BookReference::EPUB; + } else if (type == ZLMimeType::APPLICATION_MOBIPOCKET_EBOOK) { + return BookReference::MOBIPOCKET; + } + return BookReference::NONE; +} + +BookReference::Type OPDSBookItem::typeByRelation(const std::string &rel) { + if (rel == OPDSConstants::REL_ACQUISITION || rel == OPDSConstants::REL_ACQUISITION_OPEN || rel.empty()) { + return BookReference::DOWNLOAD_FULL; + } else if (rel == OPDSConstants::REL_ACQUISITION_SAMPLE) { + return BookReference::DOWNLOAD_DEMO; + } else if (rel == OPDSConstants::REL_ACQUISITION_CONDITIONAL) { + return BookReference::DOWNLOAD_FULL_CONDITIONAL; + } else if (rel == OPDSConstants::REL_ACQUISITION_SAMPLE_OR_FULL) { + return BookReference::DOWNLOAD_FULL_OR_DEMO; + } else if (rel == OPDSConstants::REL_ACQUISITION_BUY) { + return BookReference::BUY; + } else { + return BookReference::UNKNOWN; + } +} + +OPDSBookItem::FullEntryReader::FullEntryReader(OPDSBookItem &item, const OPDSLink &link, std::string url) : + myItem(item), myLink(link), myUrl(url) { +} + +void OPDSBookItem::FullEntryReader::processFeedEntry(shared_ptr<OPDSEntry> entry) { + NetworkItem::UrlInfoCollection urlMap = OPDSBookItem::getUrls(myLink, *entry, myUrl); + std::vector<shared_ptr<BookReference> > references = OPDSBookItem::getReferences(myLink, *entry, myUrl); + for (NetworkItem::UrlInfoCollection::iterator it = urlMap.begin(); it != urlMap.end(); ++it) { + myItem.URLByType[(*it).first] = (*it).second; + } + myItem.updateReferences(references); + std::string summary = OPDSBookItem::getAnnotation(*entry); + if (!summary.empty()) { + myItem.Summary = summary; + } + myItem.myRelatedInfos = OPDSBookItem::getRelatedUrls(myLink, *entry, myUrl); +} + +void OPDSBookItem::FullEntryReader::processFeedStart() { +} + +void OPDSBookItem::FullEntryReader::processFeedMetadata(shared_ptr<OPDSFeedMetadata> /*feed*/) { +} + +void OPDSBookItem::FullEntryReader::processFeedEnd() { +} + +OPDSBookItem::RelatedUrlInfo::RelatedUrlInfo(const std::string &title, shared_ptr<ZLMimeType> mimeType, const std::string url) : + Title(title), MimeType(mimeType), Url(url) { } + + diff --git a/fbreader/src/network/opds/OPDSBookItem.h b/fbreader/src/network/opds/OPDSBookItem.h new file mode 100644 index 0000000..8b3ddbd --- /dev/null +++ b/fbreader/src/network/opds/OPDSBookItem.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __OPDSBOOKITEM_H__ +#define __OPDSBOOKITEM_H__ + +#include "OPDSLink.h" +#include "OPDSMetadata.h" +#include "OPDSFeedReader.h" + +class OPDSBookItem : public NetworkBookItem { + +public: + OPDSBookItem(const OPDSLink &networkLink, OPDSEntry &entry, std::string baseUrl, unsigned int index); + +public: + bool isFullyLoaded() const; + void loadFullInformation(shared_ptr<ZLNetworkRequest::Listener> listener); + std::vector<shared_ptr<NetworkItem> > getRelatedCatalogsItems() const; + +public: + static BookReference::Format formatByZLMimeType(const std::string &mimeType); + static BookReference::Type typeByRelation(const std::string &rel); + +protected: + static std::string getAnnotation(OPDSEntry &entry); + static std::string getDate(OPDSEntry &entry); + static std::vector<AuthorData> getAuthors(OPDSEntry &entry); + static std::vector<std::string> getTags(OPDSEntry &entry); + static UrlInfoCollection getUrls(const OPDSLink &networkLink, OPDSEntry &entry, std::string baseUrl); + //TODO implement one UrlInfoCollection to not duplicate similar methods + static std::vector<shared_ptr<BookReference> > getReferences(const OPDSLink &networkLink, OPDSEntry &entry, std::string baseUrl); + +private: + class FullEntryReader : public OPDSFeedReader { + + public: + FullEntryReader(OPDSBookItem &item, const OPDSLink &link, std::string url); + + public: + void processFeedEntry(shared_ptr<OPDSEntry> entry); + void processFeedStart(); + void processFeedMetadata(shared_ptr<OPDSFeedMetadata> feed); + void processFeedEnd(); + + private: + OPDSBookItem &myItem; + const OPDSLink &myLink; + std::string myUrl; + }; + + class RelatedUrlInfo { + public: + RelatedUrlInfo(const std::string& title, shared_ptr<ZLMimeType> mimeType, const std::string url); + + std::string Title; + shared_ptr<ZLMimeType> MimeType; + std::string Url; + }; + + typedef std::vector<shared_ptr<RelatedUrlInfo> > RelatedUrlsList; + RelatedUrlsList myRelatedInfos; +protected: + static RelatedUrlsList getRelatedUrls(const OPDSLink &networkLink, OPDSEntry &entry, std::string baseUrl); +private: + bool myInformationIsFull; + +friend class OPDSBookItemFullInfoLoader; + +}; + +#endif /* __OPDSBOOKITEM_H__ */ diff --git a/fbreader/src/network/opds/OPDSCatalogItem.cpp b/fbreader/src/network/opds/OPDSCatalogItem.cpp new file mode 100644 index 0000000..853bc4c --- /dev/null +++ b/fbreader/src/network/opds/OPDSCatalogItem.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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 <ZLNetworkRequest.h> +#include <ZLNetworkManager.h> + +#include "OPDSCatalogItem.h" +#include "OPDSLink.h" +#include "OPDSXMLParser.h" +#include "NetworkOPDSFeedReader.h" + +#include "../NetworkOperationData.h" + +OPDSCatalogItem::OPDSCatalogItem( + const OPDSLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility, + int flags + ) : NetworkCatalogItem(link, title, summary, urlByType, accessibility, flags), myLoadingState(Link) { +} + +class OPDSCatalogItemRunnable : public ZLNetworkRequest::Listener { +public: + OPDSCatalogItemRunnable(shared_ptr<ZLNetworkRequest> request, NetworkItem::List &children, NetworkOperationData &data, shared_ptr<ZLNetworkRequest::Listener> listener) : + myChildren(children), myLoadingData(data), myListener(listener) { + request->setListener(this); + ZLNetworkManager::Instance().performAsync(request); + } + void finished(const std::string &error) { + myChildren.insert(myChildren.end(), myLoadingData.Items.begin(), myLoadingData.Items.end()); + myListener->finished(error); + } + void setUIStatus(bool enabled) { + myListener->setUIStatus(enabled); //to hide refreshing while authentication dialog + } + +private: + NetworkItem::List &myChildren; + NetworkOperationData &myLoadingData; + shared_ptr<ZLNetworkRequest::Listener> myListener; +}; + + +std::string OPDSCatalogItem::loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener) { + myLoadingState.clear(); + shared_ptr<ZLNetworkRequest> request = ((OPDSLink&)Link).createNetworkRequest(getCatalogUrl(), myLoadingState); + new OPDSCatalogItemRunnable(request, children, myLoadingState, listener); + return std::string(); +} + +bool OPDSCatalogItem::supportsResumeLoading() { + return true; +} + +std::string OPDSCatalogItem::resumeLoading(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener) { + shared_ptr<ZLNetworkRequest> request = myLoadingState.resume(); + if (request.isNull()) { + listener->finished(); + return std::string(); + } + new OPDSCatalogItemRunnable(request, children, myLoadingState, listener); + return std::string(); +} diff --git a/fbreader/src/network/opds/OPDSCatalogItem.h b/fbreader/src/network/opds/OPDSCatalogItem.h new file mode 100644 index 0000000..e2bc787 --- /dev/null +++ b/fbreader/src/network/opds/OPDSCatalogItem.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __OPDSCATALOGITEM_H__ +#define __OPDSCATALOGITEM_H__ + +#include <ZLExecutionUtil.h> + +#include "../NetworkItems.h" +#include "../NetworkOperationData.h" + +class OPDSLink; + +class OPDSCatalogItem : public NetworkCatalogItem { + +public: + OPDSCatalogItem( + const OPDSLink &link, + const std::string &title, + const std::string &summary, + const UrlInfoCollection &urlByType, + AccessibilityType accessibility = ALWAYS, + int flags = FLAGS_DEFAULT + ); + +public: + std::string loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener = 0); + bool supportsResumeLoading(); + std::string resumeLoading(List &children, shared_ptr<ZLNetworkRequest::Listener> listener = 0); + +private: + NetworkOperationData myLoadingState; +}; + +#endif /* __OPDSCATALOGITEM_H__ */ diff --git a/fbreader/src/network/opds/OPDSFeedReader.h b/fbreader/src/network/opds/OPDSFeedReader.h new file mode 100644 index 0000000..a842f41 --- /dev/null +++ b/fbreader/src/network/opds/OPDSFeedReader.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __OPDSFEEDREADER_H__ +#define __OPDSFEEDREADER_H__ + +#include "OPDSMetadata.h" + + +class OPDSFeedReader { + +public: + OPDSFeedReader() {} + virtual ~OPDSFeedReader() {} + +public: + virtual void processFeedEntry(shared_ptr<OPDSEntry> entry) = 0; + virtual void processFeedStart() = 0; + virtual void processFeedMetadata(shared_ptr<OPDSFeedMetadata> feed) = 0; + virtual void processFeedEnd() = 0; +}; + + +#endif /* __OPDSFEEDREADER_H__ */ diff --git a/fbreader/src/network/opds/OPDSLink.cpp b/fbreader/src/network/opds/OPDSLink.cpp new file mode 100644 index 0000000..f682b7d --- /dev/null +++ b/fbreader/src/network/opds/OPDSLink.cpp @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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 <algorithm> + +#include <ZLStringUtil.h> +#include <ZLUnicodeUtil.h> +#include <ZLNetworkUtil.h> +#include <ZLNetworkManager.h> + +#include "OPDSLink.h" +#include "OPDSLink_AdvancedSearch.h" +#include "OPDSCatalogItem.h" +#include "OPDSXMLParser.h" +#include "NetworkOPDSFeedReader.h" + +#include "../NetworkOperationData.h" +#include "../authentication/NetworkAuthenticationManager.h" +#include "../authentication/litres/LitResAuthenticationManager.h" + +#include "URLRewritingRule.h" + +OPDSLink::AdvancedSearch::AdvancedSearch( + const std::string &type, + const std::string &titleParameter, + const std::string &authorParameter, + const std::string &tagParameter, + const std::string &annotationParameter +) : myType(type), myTitleParameter(titleParameter), myAuthorParameter(authorParameter), myTagParameter(tagParameter), myAnnotationParameter(annotationParameter) { +} + +void OPDSLink::AdvancedSearch::addSubQuery(std::string &query, const std::string &name, const std::string &value) const { + if (value.empty()) { + return; + } + + if (myType == "separateWords") { + std::size_t start = 0, end; + do { + end = value.find(' ', start); + std::string ss = value.substr(start, end - start); + ZLUnicodeUtil::utf8Trim(ss); + if (!ss.empty()) { + if (!query.empty()) { + query.append("+"); + } + query.append(name + ':'); + query.append(ZLNetworkUtil::htmlEncode(ss)); + } + start = end + 1; + } while (end != std::string::npos); + } else if (myType == "quoted") { + std::string encodedValue = value; + ZLUnicodeUtil::utf8Trim(encodedValue); + + if (encodedValue.empty()) { + return; + } + encodedValue = '"' + encodedValue + '"'; + std::replace(encodedValue.begin(), encodedValue.end(), ' ', '+'); + + if (!query.empty()) { + query += '+'; + } + query += name + ':' + ZLNetworkUtil::htmlEncode(encodedValue); + } +} + +std::string OPDSLink::AdvancedSearch::query( + const std::string &titleOrSeries, + const std::string &author, + const std::string &tag, + const std::string &annotation +) const { + std::string query; + addSubQuery(query, myTitleParameter, titleOrSeries); + addSubQuery(query, myAuthorParameter, author); + addSubQuery(query, myTagParameter, tag); + addSubQuery(query, myAnnotationParameter, annotation); + return query; +} + +//shared_ptr<NetworkLink> OPDSLink::read(const ZLFile &file) { +// Reader reader; +// reader.readDocument(file); +// return reader.link(); +//} + +shared_ptr<ZLNetworkRequest> OPDSLink::createNetworkRequest(const std::string &url, NetworkOperationData &result) const { + if (url.empty()) { + return 0; + } + std::string modifiedUrl(url); + rewriteUrl(modifiedUrl); + return ZLNetworkManager::Instance().createXMLParserRequest(modifiedUrl, new OPDSXMLParser(new NetworkOPDSFeedReader(*this, url, result)) ); +} + +OPDSLink::OPDSLink( + const std::string &siteName +) : NetworkLink(siteName) { +} + +OPDSLink::~OPDSLink() { +} + +shared_ptr<NetworkItem> OPDSLink::libraryItem() const { + NetworkItem::UrlInfoCollection urlMap; + urlMap[NetworkItem::URL_COVER] = getIcon(); + urlMap[NetworkItem::URL_CATALOG] = url(URL_MAIN); + return new OPDSCatalogItem(*this, getTitle(), getSummary(), urlMap); +} + +const std::string OPDSLink::searchURL(const std::string &query) const { + return ZLStringUtil::printf(url(URL_SEARCH), query); +} + +shared_ptr<ZLNetworkRequest> OPDSLink::simpleSearchData(NetworkOperationData &result, const std::string &pattern) const { + return createNetworkRequest( + searchURL(ZLNetworkUtil::htmlEncode(pattern)), + result + ); +} + +shared_ptr<ZLNetworkRequest> OPDSLink::advancedSearchData( + NetworkOperationData &result, + const std::string &titleAndSeries, + const std::string &author, + const std::string &tag, + const std::string &annotation +) const { + if (myAdvancedSearch.isNull()) { + return 0; + } + std::string query = myAdvancedSearch->query( + titleAndSeries, author, tag, annotation + ); + return query.empty() ? 0 : createNetworkRequest(searchURL(query), result); +} + +shared_ptr<ZLNetworkRequest> OPDSLink::resume(NetworkOperationData &data) const { + const std::string url = data.ResumeURI; + return createNetworkRequest(url, data); +} + +shared_ptr<NetworkAuthenticationManager> OPDSLink::authenticationManager() const { + return myAuthenticationManager; +} + +void OPDSLink::setUrlRewritingRules(std::vector<shared_ptr<URLRewritingRule> > rules) { + myUrlRewritingRules = rules; +} + +void OPDSLink::setAuthenticationManager(shared_ptr<NetworkAuthenticationManager> manager) { + myAuthenticationManager = manager; +} + +void OPDSLink::setAdvancedSearch(shared_ptr<OPDSLink::AdvancedSearch> advancedSearch) { + myAdvancedSearch = advancedSearch; +} + +void OPDSLink::setRelationAliases(std::map<RelationAlias, std::string> relationAliases) { + myRelationAliases = relationAliases; +} + +void OPDSLink::rewriteUrl(std::string &url, bool isUrlExternal) const { + URLRewritingRule::RuleApply apply = isUrlExternal ? URLRewritingRule::EXTERNAL : URLRewritingRule::INTERNAL; + for (std::vector<shared_ptr<URLRewritingRule> >::const_iterator it = myUrlRewritingRules.begin(); it != myUrlRewritingRules.end(); ++it) { + const URLRewritingRule &rule = **it; + if (rule.whereToApply() == apply) { + url = rule.apply(url); + } + } +} + +OPDSLink::RelationAlias::RelationAlias(const std::string &alias, const std::string &type) : Alias(alias), Type(type) { +} + +bool OPDSLink::RelationAlias::operator < (const RelationAlias &alias) const { + int cmp = Alias.compare(alias.Alias); + if (cmp != 0) { + return cmp < 0; + } + return Type < alias.Type; +} + +const std::string &OPDSLink::relation(const std::string &rel, const std::string &type) const { + RelationAlias alias(rel, type); + std::map<RelationAlias,std::string>::const_iterator it = myRelationAliases.find(alias); + if (it != myRelationAliases.end()) { + return it->second; + } + if (!type.empty()) { + alias.Type.erase(); + it = myRelationAliases.find(alias); + if (it != myRelationAliases.end()) { + return it->second; + } + } + return rel; +} diff --git a/fbreader/src/network/opds/OPDSLink.h b/fbreader/src/network/opds/OPDSLink.h new file mode 100644 index 0000000..d6fd87e --- /dev/null +++ b/fbreader/src/network/opds/OPDSLink.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __OPDSLINK_H__ +#define __OPDSLINK_H__ + +#include <map> +#include <vector> +#include <string> + +#include "../NetworkLink.h" + +class ZLFile; + +class NetworkAuthenticationManager; +struct URLRewritingRule; + +class OPDSLink : public NetworkLink { + +public: + enum FeedCondition { + CONDITION_NEVER, + CONDITION_SIGNED_IN, + }; + +private: + class AdvancedSearch; + +public: + class GenericReader; + class FeedReader; + class GenericFeedReader; + class GenericXMLParser; + + OPDSLink( + const std::string &siteName + ); + +public: + ~OPDSLink(); + +private: + struct RelationAlias; + +public: + void setUrlRewritingRules(std::vector<shared_ptr<URLRewritingRule> > rules); + void setAuthenticationManager(shared_ptr<NetworkAuthenticationManager> manager); + void setAdvancedSearch(shared_ptr<OPDSLink::AdvancedSearch> advancedSearch); + void setRelationAliases(std::map<RelationAlias, std::string> relationAliases); + +private: + const std::string searchURL(const std::string &pattern) const; + + shared_ptr<ZLNetworkRequest> createNetworkRequest(const std::string &url, NetworkOperationData &result) const; + + shared_ptr<ZLNetworkRequest> simpleSearchData( + NetworkOperationData &result, + const std::string &pattern) const; + shared_ptr<ZLNetworkRequest> advancedSearchData( + NetworkOperationData &result, + const std::string &titleAndSeries, + const std::string &author, + const std::string &tag, + const std::string &annotation) const; + shared_ptr<ZLNetworkRequest> resume(NetworkOperationData &result) const; + + shared_ptr<NetworkItem> libraryItem() const; + shared_ptr<NetworkAuthenticationManager> authenticationManager() const; + + void rewriteUrl(std::string &url, bool isUrlExternal = false) const; + + const std::string &relation(const std::string &rel, const std::string &type) const; + +private: + shared_ptr<AdvancedSearch> myAdvancedSearch; + + struct RelationAlias { + std::string Alias; + std::string Type; + + RelationAlias(const std::string &alias, const std::string &type); + bool operator < (const RelationAlias &other) const; + }; + std::map<RelationAlias, std::string> myRelationAliases; + + std::map<std::string,FeedCondition> myFeedConditions; + std::vector<shared_ptr<URLRewritingRule> > myUrlRewritingRules; + + shared_ptr<NetworkAuthenticationManager> myAuthenticationManager; + +friend class NetworkOPDSFeedReader; +friend class OPDSCatalogItem; +friend class OPDSBookItem; +}; + +#endif /* __OPDSLINK_H__ */ diff --git a/fbreader/src/network/opds/OPDSLink_AdvancedSearch.h b/fbreader/src/network/opds/OPDSLink_AdvancedSearch.h new file mode 100644 index 0000000..76519c9 --- /dev/null +++ b/fbreader/src/network/opds/OPDSLink_AdvancedSearch.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __OPDSLINK_ADVANCEDSEARCH_H__ +#define __OPDSLINK_ADVANCEDSEARCH_H__ + +#include <string> +/* +#include <algorithm> + +#include <ZLStringUtil.h> +#include <ZLNetworkUtil.h> +#include <ZLNetworkManager.h> + +#include "OPDSLink.h" +#include "OPDSLinkReader.h" +#include "OPDSCatalogItem.h" +#include "OPDSXMLParser.h" +#include "NetworkOPDSFeedReader.h" + +#include "../NetworkOperationData.h" +#include "../authentication/NetworkAuthenticationManager.h" + +#include "URLRewritingRule.h" +*/ + +class OPDSLink::AdvancedSearch { + +public: + AdvancedSearch( + const std::string &type, + const std::string &titleParameter, + const std::string &authorParameter, + const std::string &tagParameter, + const std::string &annotationParameter + ); + + std::string query( + const std::string &titleOrSeries, + const std::string &author, + const std::string &tag, + const std::string &annotation + ) const; + +private: + void addSubQuery(std::string &query, const std::string &name, const std::string &value) const; + +private: + const std::string myType; + const std::string myTitleParameter; + const std::string myAuthorParameter; + const std::string myTagParameter; + const std::string myAnnotationParameter; +}; + +#endif /* __OPDSLINK_ADVANCEDSEARCH_H__ */ diff --git a/fbreader/src/network/opds/OPDSLink_GenericFeedReader.cpp b/fbreader/src/network/opds/OPDSLink_GenericFeedReader.cpp new file mode 100644 index 0000000..5389f2d --- /dev/null +++ b/fbreader/src/network/opds/OPDSLink_GenericFeedReader.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <[email protected]> + * + * 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 <ZLStringUtil.h> +#include <ZLMimeType.h> +#include <ZLNetworkRequest.h> +#include <ZLNetworkManager.h> + +#include "../authentication/litres/LitResAuthenticationManager.h" + +#include "OPDSLink_GenericFeedReader.h" +#include "OpenSearchXMLReader.h" + +OPDSLink::GenericFeedReader::GenericFeedReader( + std::vector<shared_ptr<NetworkLink> >& links +) : + myLinks(links) { +} + +void OPDSLink::GenericFeedReader::processFeedStart() { +} + +void OPDSLink::GenericFeedReader::processFeedMetadata(shared_ptr<OPDSFeedMetadata>) { + +} + + +void OPDSLink::GenericFeedReader::processFeedEnd() { +} + +void OPDSLink::GenericFeedReader::processFeedEntry(shared_ptr<OPDSEntry> entry) { + std::map<std::string,std::string> links; + std::string iconURL; + for (std::size_t i = 0; i < entry->links().size(); ++i) { + ATOMLink &link = *(entry->links()[i]); + const std::string &href = link.href(); + const std::string &rel = link.rel(); + shared_ptr<ZLMimeType> type = ZLMimeType::get(link.type()); + if (rel == NetworkLink::URL_SEARCH) { + links[rel] = OpenSearchXMLReader::convertOpenSearchURL(href); + } else if (rel == "") { + links[NetworkLink::URL_MAIN] = href; + } else if (rel == OPDSConstants::REL_LINK_SIGN_IN) { + links[NetworkLink::URL_SIGN_IN] = href; + } else if (rel == OPDSConstants::REL_LINK_SIGN_OUT) { + links[NetworkLink::URL_SIGN_OUT] = href; + } else if (rel == OPDSConstants::REL_LINK_SIGN_UP) { + links[NetworkLink::URL_SIGN_UP] = href; + } else if (rel == OPDSConstants::REL_LINK_TOPUP) { + links[NetworkLink::URL_TOPUP] = href; + } else if (rel == OPDSConstants::REL_LINK_RECOVER_PASSWORD) { + links[NetworkLink::URL_RECOVER_PASSWORD] = href; + } else if (rel == OPDSConstants::REL_THUMBNAIL || rel == OPDSConstants::REL_IMAGE_THUMBNAIL) { + if (ZLMimeType::isImage(type)) { + iconURL = href; + } + } else if (iconURL.empty() && (rel == OPDSConstants::REL_COVER || ZLStringUtil::stringStartsWith(rel, OPDSConstants::REL_IMAGE_PREFIX))) { + if (ZLMimeType::isImage(type)) { + iconURL = href; + } + } else { + links[rel] = href; + } + } + if (entry->title().empty() || links[NetworkLink::URL_MAIN].empty()) { + return; + } + if (entry->id() == 0) { + return; + } + std::string id = entry->id()->uri(); + std::string summary = entry->summary(); + std::string language = entry->dcLanguage(); + + shared_ptr<NetworkLink> link = new OPDSLink(id.substr(25)); //why just 25 symbols? + link->setTitle(entry->title()); + link->setSummary(summary); + link->setLanguage(language); + link->setIcon(iconURL); + link->setLinks(links); + link->setPredefinedId(id); + link->setUpdated(entry->updated()); + + OPDSLink &opdsLink = static_cast<OPDSLink&>(*link); + opdsLink.setUrlRewritingRules(myUrlRewritingRules); + if (!myAdvancedSearch.isNull()) { + opdsLink.setAdvancedSearch(myAdvancedSearch); + } + opdsLink.setRelationAliases(myRelationAliases); + if (myAuthenticationType == "litres") { + opdsLink.setAuthenticationManager(new LitResAuthenticationManager(*link)); + } + myLinks.push_back(link); +} + +void OPDSLink::GenericFeedReader::clear() { + myAuthenticationType.clear(); + myUrlRewritingRules.clear(); + myAdvancedSearch.reset(); + myRelationAliases.clear(); +} + +void OPDSLink::GenericFeedReader::setAdvancedSearch(shared_ptr<OPDSLink::AdvancedSearch> advancedSearch) { + myAdvancedSearch = advancedSearch; +} + +void OPDSLink::GenericFeedReader::setAuthenticationType(std::string type) { + myAuthenticationType = type; +} + +void OPDSLink::GenericFeedReader::addUrlRewritingRule(shared_ptr<URLRewritingRule> rewritingRule) { + myUrlRewritingRules.push_back(rewritingRule); +} + +void OPDSLink::GenericFeedReader::addRelationAlias(const OPDSLink::RelationAlias& alias, std::string name) { + myRelationAliases[alias] = name; +} diff --git a/fbreader/src/network/opds/OPDSLink_GenericFeedReader.h b/fbreader/src/network/opds/OPDSLink_GenericFeedReader.h new file mode 100644 index 0000000..15ffe38 --- /dev/null +++ b/fbreader/src/network/opds/OPDSLink_GenericFeedReader.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __OPDSLINK_GENERICFEEDREADER_H__ +#define __OPDSLINK_GENERICFEEDREADER_H__ + +#include <map> +#include <string> + +#include "URLRewritingRule.h" +#include "OPDSFeedReader.h" +#include "OPDSLink.h" +#include "OPDSLink_AdvancedSearch.h" + +class OPDSLink::GenericFeedReader : public OPDSFeedReader { + +public: + GenericFeedReader( + std::vector<shared_ptr<NetworkLink> >& links + ); + +public: + void processFeedEntry(shared_ptr<OPDSEntry> entry); + void processFeedStart(); + void processFeedMetadata(shared_ptr<OPDSFeedMetadata> feed); + void processFeedEnd(); + +public: + void clear(); + void setAdvancedSearch(shared_ptr<OPDSLink::AdvancedSearch> advancedSearch); + void setAuthenticationType(std::string type); + void addUrlRewritingRule(shared_ptr<URLRewritingRule> rewritingRule); + void addRelationAlias(const OPDSLink::RelationAlias&, std::string name); + +private: + std::vector<shared_ptr<NetworkLink> >& myLinks; + +private: + std::string myAuthenticationType; + std::vector<shared_ptr<URLRewritingRule> > myUrlRewritingRules; + shared_ptr<OPDSLink::AdvancedSearch> myAdvancedSearch; + std::map<OPDSLink::RelationAlias,std::string> myRelationAliases; +}; + +#endif /* __OPDSLINK_GENERICFEEDREADER_H__ */ diff --git a/fbreader/src/network/opds/OPDSLink_GenericXMLParser.cpp b/fbreader/src/network/opds/OPDSLink_GenericXMLParser.cpp new file mode 100644 index 0000000..ef67116 --- /dev/null +++ b/fbreader/src/network/opds/OPDSLink_GenericXMLParser.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <[email protected]> + * + * 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 <ZLXMLNamespace.h> + +#include "OPDSLink_GenericXMLParser.h" +#include "URLRewritingRule.h" +#include "OPDSLink_AdvancedSearch.h" + +static const std::string TAG_ENTRY = "entry"; +static const std::string FBREADER_ADVANCED_SEARCH = "advancedSearch"; +static const std::string FBREADER_AUTHENTICATION = "authentication"; +static const std::string FBREADER_REWRITING_RULE = "urlRewritingRule"; +static const std::string FBREADER_RELATION_ALIAS = "relationAlias"; +static const std::string FBREADER_EXTRA = "extra"; + +OPDSLink::GenericXMLParser::GenericXMLParser(shared_ptr<OPDSFeedReader> feedReader) : + OPDSXMLParser(feedReader) { +} + +OPDSLink::GenericFeedReader &OPDSLink::GenericXMLParser::getFeedReader() const { + return static_cast<OPDSLink::GenericFeedReader&>(*myFeedReader); +} + +void OPDSLink::GenericXMLParser::startElementHandler(const char *tag, const char **attributes) { + switch (myState) { + case FEED: + if (testTag(ZLXMLNamespace::Atom, TAG_ENTRY, tag)) { + getFeedReader().clear(); + } + break; + case F_ENTRY: + if (testTag(ZLXMLNamespace::FBReaderCatalogMetadata, FBREADER_ADVANCED_SEARCH, tag)) { + const char *style = attributeValue(attributes, "style"); + const char *author = attributeValue(attributes, "author"); + const char *titleOrSeries = attributeValue(attributes, "titleOrSeries"); + const char *tag = attributeValue(attributes, "tag"); + const char *annotation = attributeValue(attributes, "annotation"); + if (style != 0 && author != 0 && titleOrSeries != 0 && tag != 0 && annotation != 0) { + getFeedReader().setAdvancedSearch(new OPDSLink::AdvancedSearch(style, titleOrSeries, author, tag, annotation)); + } + return; + } else if (testTag(ZLXMLNamespace::FBReaderCatalogMetadata, FBREADER_AUTHENTICATION, tag)) { + const char *type = attributeValue(attributes, "type"); + if (type != 0) { + getFeedReader().setAuthenticationType(type); + } + return; + } else if (testTag(ZLXMLNamespace::FBReaderCatalogMetadata, FBREADER_RELATION_ALIAS, tag)) { + const char *name = attributeValue(attributes, "name"); + const char *type = attributeValue(attributes, "type"); + const char *alias = attributeValue(attributes, "alias"); + if (name != 0 && alias != 0) { + getFeedReader().addRelationAlias(OPDSLink::RelationAlias(alias, (type != 0) ? type : std::string()), name); + } + } else if (testTag(ZLXMLNamespace::FBReaderCatalogMetadata, FBREADER_REWRITING_RULE, tag)) { + + getFeedReader().addUrlRewritingRule(new URLRewritingRule(getAttributesMap(attributes))); + +// const char *type = attributeValue(attributes, "type"); +// const char *apply = attributeValue(attributes, "apply"); +// const char *name = attributeValue(attributes, "name"); +// const char *value = attributeValue(attributes, "value"); + +// //TODO add rewrite type of 'rewriting rules' +// URLRewritingRule::RuleApply ruleApply = URLRewritingRule::ALWAYS; +// if (apply != 0) { +// const std::string applyStr = apply; +// if (applyStr == "external") { +// ruleApply = URLRewritingRule::EXTERNAL; +// } else if (applyStr == "internal") { +// ruleApply = URLRewritingRule::INTERNAL; +// } else if (applyStr != "always") { +// type = 0; +// } +// } + +// if (type != 0 && name != 0 && value != 0) { +// std::string typeStr = type; +// if (typeStr == "addUrlParameter") { +// getFeedReader().addUrlRewritingRule(new URLRewritingRule(URLRewritingRule::ADD_URL_PARAMETER, ruleApply, name, value)); +// } +// } + + return; + } + break; + default: + break; + } + OPDSXMLParser::startElementHandler(tag, attributes); +} + diff --git a/fbreader/src/network/opds/OPDSLink_GenericXMLParser.h b/fbreader/src/network/opds/OPDSLink_GenericXMLParser.h new file mode 100644 index 0000000..9bdf9d6 --- /dev/null +++ b/fbreader/src/network/opds/OPDSLink_GenericXMLParser.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __OPDSLINK_GENERICXMLPARSER_H__ +#define __OPDSLINK_GENERICXMLPARSER_H__ + +#include "OPDSXMLParser.h" +#include "OPDSLink_GenericFeedReader.h" + +class OPDSLink::GenericXMLParser : public OPDSXMLParser { +public: + GenericXMLParser(shared_ptr<OPDSFeedReader> feedReader); + +protected: + void startElementHandler(const char *tag, const char **attributes); + OPDSLink::GenericFeedReader &getFeedReader() const; +}; + +#endif /* __OPDSLINK_GENERICXMLPARSER_H__ */ diff --git a/fbreader/src/network/opds/OPDSMetadata.cpp b/fbreader/src/network/opds/OPDSMetadata.cpp new file mode 100644 index 0000000..6595e05 --- /dev/null +++ b/fbreader/src/network/opds/OPDSMetadata.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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 "OPDSMetadata.h" + +// Feed level +const std::string OPDSConstants::REL_BOOKSHELF = "http://data.fbreader.org/rel/bookshelf"; +const std::string OPDSConstants::REL_RECOMMENDATIONS = "http://data.fbreader.org/rel/recommendations"; + +//const std::string OPDSConstants::REL_SUBSCRIPTIONS = "http://opds-spec.org/subscriptions"; + +const std::string OPDSConstants::REL_CATALOG_AUTHOR = "http://data.fbreader.org/catalog/author"; +const std::string OPDSConstants::REL_ACQUISITION = "http://opds-spec.org/acquisition"; +const std::string OPDSConstants::REL_ACQUISITION_OPEN = "http://opds-spec.org/acquisition/open-access"; +const std::string OPDSConstants::REL_ACQUISITION_BUY = "http://opds-spec.org/acquisition/buy"; +//const std::string OPDSConstants::REL_ACQUISITION_BORROW = "http://opds-spec.org/acquisition/borrow"; +//const std::string OPDSConstants::REL_ACQUISITION_SUBSCRIBE = "http://opds-spec.org/acquisition/subscribe"; +const std::string OPDSConstants::REL_ACQUISITION_SAMPLE = "http://opds-spec.org/acquisition/sample"; +const std::string OPDSConstants::REL_ACQUISITION_CONDITIONAL = "http://data.fbreader.org/acquisition/conditional"; +const std::string OPDSConstants::REL_ACQUISITION_SAMPLE_OR_FULL = "http://data.fbreader.org/acquisition/sampleOrFull"; + +// Entry level / other +const std::string OPDSConstants::REL_IMAGE_PREFIX = "http://opds-spec.org/image"; +//const std::string OPDSConstants::REL_IMAGE = "http://opds-spec.org/image"; +const std::string OPDSConstants::REL_IMAGE_THUMBNAIL = "http://opds-spec.org/image/thumbnail"; +// FIXME: This relations have been removed from OPDS-1.0 standard. Use RelationAlias instead??? +const std::string OPDSConstants::REL_COVER = "http://opds-spec.org/cover"; +const std::string OPDSConstants::REL_THUMBNAIL = "http://opds-spec.org/thumbnail"; + +// Entry level / OPDS Link Relations +const std::string OPDSConstants::REL_LINK_SIGN_IN = "http://data.fbreader.org/catalog/sign-in"; +const std::string OPDSConstants::REL_LINK_SIGN_OUT = "http://data.fbreader.org/catalog/sign-out"; +const std::string OPDSConstants::REL_LINK_SIGN_UP = "http://data.fbreader.org/catalog/sign-up"; +const std::string OPDSConstants::REL_LINK_TOPUP = "http://data.fbreader.org/catalog/refill-account"; +const std::string OPDSConstants::REL_LINK_RECOVER_PASSWORD = "http://data.fbreader.org/catalog/recover-password"; + +DCDate::DCDate() : + ATOMDateConstruct(0) { +} + +DCDate::DCDate(int year) : + ATOMDateConstruct(year) { +} + +DCDate::DCDate(int year, int month, int day) : + ATOMDateConstruct(year, month, day) { +} + +DCDate::DCDate(int year, int month, int day, int hour, int minutes, int seconds) : + ATOMDateConstruct(year, month, day, hour, minutes, seconds) { +} + +DCDate::DCDate(int year, int month, int day, int hour, int minutes, int seconds, float sfract) : + ATOMDateConstruct(year, month, day, hour, minutes, seconds, sfract) { +} + +DCDate::DCDate(int year, int month, int day, int hour, int minutes, int seconds, float sfract, int tzhour, int tzminutes) : + ATOMDateConstruct(year, month, day, hour, minutes, seconds, sfract, tzhour, tzminutes) { +} + +OPDSEntry::OPDSEntry() { +} + +OPDSEntry::OPDSEntry(shared_ptr<ATOMId> id, const std::string &title, shared_ptr<ATOMUpdated> updated) : + ATOMEntry(id, title, updated) { +} + +OPDSFeedMetadata::OPDSFeedMetadata() : myOpensearchTotalResults(0), myOpensearchItemsPerPage(0), myOpensearchStartIndex(1) { +} + +OPDSFeedMetadata::OPDSFeedMetadata(shared_ptr<ATOMId> id, const std::string &title, shared_ptr<ATOMUpdated> updated) : + ATOMFeedMetadata(id, title, updated), myOpensearchTotalResults(0), myOpensearchItemsPerPage(0), myOpensearchStartIndex(1) { +} diff --git a/fbreader/src/network/opds/OPDSMetadata.h b/fbreader/src/network/opds/OPDSMetadata.h new file mode 100644 index 0000000..51554dd --- /dev/null +++ b/fbreader/src/network/opds/OPDSMetadata.h @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __OPDSMETADATA_H__ +#define __OPDSMETADATA_H__ + +#include <map> + +#include "../atom/ATOMContainers.h" + + +class OPDSConstants { + +private: + OPDSConstants(); + +public: + + //TODO get other relations from FBReaderJ + + // Feed level + static const std::string REL_BOOKSHELF; + static const std::string REL_RECOMMENDATIONS; + + //static const std::string REL_SUBSCRIPTIONS; + + // Entry level / catalog types + static const std::string REL_CATALOG_AUTHOR; + + // Entry level / acquisition links + static const std::string REL_ACQUISITION; + static const std::string REL_ACQUISITION_OPEN; + static const std::string REL_ACQUISITION_BUY; +// static const std::string REL_ACQUISITION_BORROW; +// static const std::string REL_ACQUISITION_SUBSCRIBE; + static const std::string REL_ACQUISITION_SAMPLE; + static const std::string REL_ACQUISITION_CONDITIONAL; + static const std::string REL_ACQUISITION_SAMPLE_OR_FULL; + + // Entry level / other + static const std::string REL_IMAGE_PREFIX; + //static const std::string REL_IMAGE; + static const std::string REL_IMAGE_THUMBNAIL; + static const std::string REL_COVER; + static const std::string REL_THUMBNAIL; + + // Entry level / OPDS Link Relations + static const std::string REL_LINK_SIGN_IN; + static const std::string REL_LINK_SIGN_OUT; + static const std::string REL_LINK_SIGN_UP; + static const std::string REL_LINK_TOPUP; + static const std::string REL_LINK_RECOVER_PASSWORD; +}; + + +class DCDate : public ATOMDateConstruct { + +public: + DCDate(); + DCDate(int year); + DCDate(int year, int month, int day); + DCDate(int year, int month, int day, int hour, int minutes, int seconds); + DCDate(int year, int month, int day, int hour, int minutes, int seconds, float sfract); + DCDate(int year, int month, int day, int hour, int minutes, int seconds, float sfract, int tzhour, int tzminutes); +}; + +class OPDSEntry : public ATOMEntry { + +public: + OPDSEntry(); + OPDSEntry(shared_ptr<ATOMId> id, const std::string &title, shared_ptr<ATOMUpdated> updated); + + const std::string &dcLanguage() const { return myDCLanguage; } + const std::string &dcPublisher() const { return myDCPublisher; } + shared_ptr<DCDate> dcIssued() { return myDCIssued; } + const std::string &seriesTitle() const { return mySeriesTitle; } + int seriesIndex() const { return mySeriesIndex; } + + void setDCLanguage(const std::string &language) { myDCLanguage = language; } + void setDCPublisher(const std::string &publisher) { myDCPublisher = publisher; } + void setDCIssued(shared_ptr<DCDate> issued) { myDCIssued = issued; } + void setSeriesTitle(const std::string &seriesTitle) { mySeriesTitle = seriesTitle; } + void setSeriesIndex(int seriesIndex) { mySeriesIndex = seriesIndex; } + +private: + std::string myDCLanguage; + std::string myDCPublisher; + shared_ptr<DCDate> myDCIssued; + + std::string mySeriesTitle; + int mySeriesIndex; +}; + + + +class OPDSFeedMetadata : public ATOMFeedMetadata { + +public: + OPDSFeedMetadata(); + OPDSFeedMetadata(shared_ptr<ATOMId> id, const std::string &title, shared_ptr<ATOMUpdated> updated); + + unsigned long getOpensearchTotalResults() const; + unsigned long getOpensearchItemsPerPage() const; + unsigned long getOpensearchStartIndex() const; + + void setOpensearchTotalResults(unsigned long number); + void setOpensearchItemsPerPage(unsigned long number); + void setOpensearchStartIndex(unsigned long number); + +private: + unsigned long myOpensearchTotalResults; + unsigned long myOpensearchItemsPerPage; + unsigned long myOpensearchStartIndex; +}; + +inline unsigned long OPDSFeedMetadata::getOpensearchTotalResults() const { return myOpensearchTotalResults; } +inline unsigned long OPDSFeedMetadata::getOpensearchItemsPerPage() const { return myOpensearchItemsPerPage; } +inline unsigned long OPDSFeedMetadata::getOpensearchStartIndex() const { return myOpensearchStartIndex; } +inline void OPDSFeedMetadata::setOpensearchTotalResults(unsigned long number) { myOpensearchTotalResults = number; } +inline void OPDSFeedMetadata::setOpensearchItemsPerPage(unsigned long number) { myOpensearchItemsPerPage = number; } +inline void OPDSFeedMetadata::setOpensearchStartIndex(unsigned long number) { myOpensearchStartIndex = number; } + +#endif /* __OPDSMETADATA_H__ */ diff --git a/fbreader/src/network/opds/OPDSXMLParser.cpp b/fbreader/src/network/opds/OPDSXMLParser.cpp new file mode 100644 index 0000000..a1a1dd9 --- /dev/null +++ b/fbreader/src/network/opds/OPDSXMLParser.cpp @@ -0,0 +1,554 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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 <cstdlib> + +#include <ZLUnicodeUtil.h> +#include <ZLXMLNamespace.h> + +#include "OPDSXMLParser.h" + +static const std::string TAG_FEED = "feed"; +static const std::string TAG_ENTRY = "entry"; +static const std::string TAG_AUTHOR = "author"; +static const std::string TAG_NAME = "name"; +static const std::string TAG_URI = "uri"; +static const std::string TAG_EMAIL = "email"; +static const std::string TAG_ID = "id"; +static const std::string TAG_CATEGORY = "category"; +static const std::string TAG_LINK = "link"; +static const std::string TAG_PUBLISHED = "published"; +static const std::string TAG_SUMMARY = "summary"; +static const std::string TAG_CONTENT = "content"; +static const std::string TAG_SUBTITLE = "subtitle"; +static const std::string TAG_TITLE = "title"; +static const std::string TAG_UPDATED = "updated"; +static const std::string TAG_PRICE = "price"; +static const std::string TAG_ICON = "icon"; + +static const std::string TAG_HACK_SPAN = "span"; + +static const std::string DC_TAG_LANGUAGE = "language"; +static const std::string DC_TAG_ISSUED = "issued"; +static const std::string DC_TAG_PUBLISHER = "publisher"; +static const std::string DC_TAG_FORMAT = "format"; + +static const std::string CALIBRE_TAG_SERIES = "series"; +static const std::string CALIBRE_TAG_SERIES_INDEX = "series_index"; + +static const std::string OPENSEARCH_TAG_TOTALRESULTS = "totalResults"; +static const std::string OPENSEARCH_TAG_ITEMSPERPAGE = "itemsPerPage"; +static const std::string OPENSEARCH_TAG_STARTINDEX = "startIndex"; + +const std::string OPDSXMLParser::KEY_PRICE = "price"; +const std::string OPDSXMLParser::KEY_CURRENCY = "currency"; +const std::string OPDSXMLParser::KEY_FORMAT = "format"; + +static const std::string TAG_SEARCH_DESCRIPTION = "fbreader:advancedSearch"; +static const std::string TAG_AUTHENTICATION = "fbreader:authentication"; +static const std::string TAG_URL_REWRITING_RULES = "fbreader:urlRewritingRule"; +static const std::string TAG_RELATION_ALIASES = "fbreader:relationAlias"; + +OPDSXMLParser::OPDSXMLParser(shared_ptr<OPDSFeedReader> feedReader, bool readEntryNotFeed) : myFeedReader(feedReader) { + myState = readEntryNotFeed ? FEED : START; +} + +bool OPDSXMLParser::processNamespaces() const { + return true; +} + +void OPDSXMLParser::startElementHandler(const char *tag, const char **attributes) { + std::map<std::string,std::string> attributeMap = getAttributesMap(attributes); + switch (myState) { + case START: + if (testTag(ZLXMLNamespace::Atom, TAG_FEED, tag)) { + myFeedReader->processFeedStart(); + myFeed = new OPDSFeedMetadata(); + myFeed->readAttributes(attributeMap); + myState = FEED; + } + break; + case FEED: + if (testTag(ZLXMLNamespace::Atom, TAG_AUTHOR, tag)) { + myAuthor = new ATOMAuthor(); + myAuthor->readAttributes(attributeMap); + myState = F_AUTHOR; + } else if (testTag(ZLXMLNamespace::Atom, TAG_ID, tag)) { + myId = new ATOMId(); + myId->readAttributes(attributeMap); + myState = F_ID; + } else if (testTag(ZLXMLNamespace::Atom, TAG_ICON, tag)) { + myIcon = new ATOMIcon(); + myIcon->readAttributes(attributeMap); + myState = F_ICON; + } else if (testTag(ZLXMLNamespace::Atom, TAG_LINK, tag)) { + myLink = new ATOMLink(); + myLink->readAttributes(attributeMap); + myState = F_LINK; + } else if (testTag(ZLXMLNamespace::Atom, TAG_CATEGORY, tag)) { + myCategory = new ATOMCategory(); + myCategory->readAttributes(attributeMap); + myState = F_CATEGORY; + } else if (testTag(ZLXMLNamespace::Atom, TAG_TITLE, tag)) { + //myTitle = new ATOMTitle(); // TODO:implement ATOMTextConstruct & ATOMTitle + //myTitle->readAttributes(attributeMap); + myState = F_TITLE; + } else if (testTag(ZLXMLNamespace::Atom, TAG_SUBTITLE, tag)) { + myState = F_SUBTITLE; + } else if (testTag(ZLXMLNamespace::Atom, TAG_SUMMARY, tag)) { + myState = F_SUMMARY; + } else if (testTag(ZLXMLNamespace::Atom, TAG_UPDATED, tag)) { + myUpdated = new ATOMUpdated(); + myUpdated->readAttributes(attributeMap); + myState = F_UPDATED; + } else if (testTag(ZLXMLNamespace::Atom, TAG_ENTRY, tag)) { + myEntry = new OPDSEntry(); + myEntry->readAttributes(attributeMap); + mySummaryTagFound = false; + myState = F_ENTRY; + } else if (testTag(ZLXMLNamespace::OpenSearch, OPENSEARCH_TAG_TOTALRESULTS, tag)) { + myState = OPENSEARCH_TOTALRESULTS; + } else if (testTag(ZLXMLNamespace::OpenSearch, OPENSEARCH_TAG_ITEMSPERPAGE, tag)) { + myState = OPENSEARCH_ITEMSPERPAGE; + } else if (testTag(ZLXMLNamespace::OpenSearch, OPENSEARCH_TAG_STARTINDEX, tag)) { + myState = OPENSEARCH_STARTINDEX; + } + break; + case F_ENTRY: + if (testTag(ZLXMLNamespace::Atom, TAG_AUTHOR, tag)) { + myAuthor = new ATOMAuthor(); + myAuthor->readAttributes(attributeMap); + myState = FE_AUTHOR; + } else if (testTag(ZLXMLNamespace::Atom, TAG_ID, tag)) { + myId = new ATOMId(); + myId->readAttributes(attributeMap); + myState = FE_ID; + } else if (testTag(ZLXMLNamespace::Atom, TAG_CATEGORY, tag)) { + myCategory = new ATOMCategory(); + myCategory->readAttributes(attributeMap); + myState = FE_CATEGORY; + } else if (testTag(ZLXMLNamespace::Atom, TAG_ICON, tag)) { + myIcon = new ATOMIcon(); + myIcon->readAttributes(attributeMap); + myState = FE_ICON; + } else if (testTag(ZLXMLNamespace::Atom, TAG_LINK, tag)) { + myLink = new ATOMLink(); + myLink->readAttributes(attributeMap); + myState = FE_LINK; + } else if (testTag(ZLXMLNamespace::Atom, TAG_PUBLISHED, tag)) { + myPublished = new ATOMPublished(); + myPublished->readAttributes(attributeMap); + myState = FE_PUBLISHED; + } else if (testTag(ZLXMLNamespace::Atom, TAG_SUMMARY, tag)) { + //mySummary = new ATOMSummary(); // TODO:implement ATOMTextConstruct & ATOMSummary + //mySummary->readAttributes(attributeMap); + myState = FE_SUMMARY; + } else if (testTag(ZLXMLNamespace::Atom, TAG_CONTENT, tag)) { + // ??? + myState = FE_CONTENT; + } else if (testTag(ZLXMLNamespace::Atom, TAG_SUBTITLE, tag)) { + // ??? + myState = FE_SUBTITLE; + } else if (testTag(ZLXMLNamespace::Atom, TAG_TITLE, tag)) { + //myTitle = new ATOMTitle(); // TODO:implement ATOMTextConstruct & ATOMTitle + //myTitle->readAttributes(attributeMap); + myState = FE_TITLE; + } else if (testTag(ZLXMLNamespace::Atom, TAG_UPDATED, tag)) { + myUpdated = new ATOMUpdated(); + myUpdated->readAttributes(attributeMap); + myState = FE_UPDATED; + } else if (testTag(ZLXMLNamespace::DublinCoreTerms, DC_TAG_LANGUAGE, tag)) { + myState = FE_DC_LANGUAGE; + } else if (testTag(ZLXMLNamespace::DublinCoreTerms, DC_TAG_ISSUED, tag)) { + myState = FE_DC_ISSUED; + } else if (testTag(ZLXMLNamespace::DublinCoreTerms, DC_TAG_PUBLISHER, tag)) { + myState = FE_DC_PUBLISHER; + } else if (testTag(ZLXMLNamespace::CalibreMetadata, CALIBRE_TAG_SERIES, tag)) { + myState = FE_CALIBRE_SERIES; + } else if (testTag(ZLXMLNamespace::CalibreMetadata, CALIBRE_TAG_SERIES_INDEX, tag)) { + myState = FE_CALIBRE_SERIES_INDEX; + } + break; + case F_AUTHOR: + if (testTag(ZLXMLNamespace::Atom, TAG_NAME, tag)) { + myState = FA_NAME; + } else if (testTag(ZLXMLNamespace::Atom, TAG_URI, tag)) { + myState = FA_URI; + } else if (testTag(ZLXMLNamespace::Atom, TAG_EMAIL, tag)) { + myState = FA_EMAIL; + } + break; + case FE_TITLE: + // TODO: remove this temporary code + // DON'T clear myBuffer + return; + case FE_LINK: + if (testTag(ZLXMLNamespace::Opds, TAG_PRICE, tag)) { + myLink->setUserData(KEY_CURRENCY, attributeMap["currencycode"]); + myState = FEL_PRICE; + } if (testTag(ZLXMLNamespace::DublinCoreTerms, DC_TAG_FORMAT, tag)) { + myState = FEL_FORMAT; + } + break; + case FE_AUTHOR: + if (testTag(ZLXMLNamespace::Atom, TAG_NAME, tag)) { + myState = FEA_NAME; + } else if (testTag(ZLXMLNamespace::Atom, TAG_URI, tag)) { + myState = FEA_URI; + } else if (testTag(ZLXMLNamespace::Atom, TAG_EMAIL, tag)) { + myState = FEA_EMAIL; + } + break; + case FE_CONTENT: + if (TAG_HACK_SPAN == tag || attributeMap["class"] == "price") { + myState = FEC_HACK_SPAN; + } + break; + default: + break; + } + + myBuffer.clear(); +} + +void OPDSXMLParser::endElementHandler(const char *tag) { + ZLUnicodeUtil::utf8Trim(myBuffer); + + switch (myState) { + case START: + break; + case FEED: + if (testTag(ZLXMLNamespace::Atom, TAG_FEED, tag)) { + myFeedReader->processFeedMetadata(myFeed); + myFeed.reset(); + myFeedReader->processFeedEnd(); + myState = START; + } + break; + case F_ENTRY: + if (testTag(ZLXMLNamespace::Atom, TAG_ENTRY, tag)) { + myFeedReader->processFeedEntry(myEntry); + myEntry.reset(); + myState = FEED; + } + break; + case F_ID: + if (testTag(ZLXMLNamespace::Atom, TAG_ID, tag)) { + // FIXME:uri can be lost:buffer will be truncated, if there are extension tags inside the <id> tag + myId->setUri(myBuffer); + if (!myFeed.isNull()) { + myFeed->setId(myId); + } + myId.reset(); + myState = FEED; + } + break; + case F_ICON: + if (testTag(ZLXMLNamespace::Atom, TAG_ICON, tag)) { + myIcon->setUri(myBuffer); + if (!myFeed.isNull()) { + myFeed->setIcon(myIcon); + } + myIcon.reset(); + myState = FEED; + } + break; + case F_LINK: + if (testTag(ZLXMLNamespace::Atom, TAG_LINK, tag)) { + if (!myFeed.isNull()) { + myFeed->links().push_back(myLink); + } + myLink.reset(); + myState = FEED; + } + break; + case F_CATEGORY: + if (testTag(ZLXMLNamespace::Atom, TAG_CATEGORY, tag)) { + if (!myFeed.isNull()) { + myFeed->categories().push_back(myCategory); + } + myCategory.reset(); + myState = FEED; + } + break; + case F_TITLE: + if (testTag(ZLXMLNamespace::Atom, TAG_TITLE, tag)) { + // FIXME:title can be lost:buffer will be truncated, if there are extension tags inside the <title> tag + // TODO:implement ATOMTextConstruct & ATOMTitle + if (!myFeed.isNull()) { + myFeed->setTitle(myBuffer); + } + myState = FEED; + } + break; + case F_SUBTITLE: + if (testTag(ZLXMLNamespace::Atom, TAG_SUBTITLE, tag)) { + if (!myFeed.isNull()) { + myFeed->setSubtitle(myBuffer); + } + myState = FEED; + } + break; + case F_SUMMARY: + if (testTag(ZLXMLNamespace::Atom, TAG_SUMMARY, tag)) { + if (!myFeed.isNull()) { + myFeed->setSummary(myBuffer); + } + myState = FEED; + } + break; + case F_UPDATED: + if (testTag(ZLXMLNamespace::Atom, TAG_UPDATED, tag)) { + // FIXME:uri can be lost:buffer will be truncated, if there are extension tags inside the <id> tag + ATOMDateConstruct::parse(myBuffer, *myUpdated); + if (!myFeed.isNull()) { + myFeed->setUpdated(myUpdated); + } + myUpdated.reset(); + myState = FEED; + } + break; + case F_AUTHOR: + if (testTag(ZLXMLNamespace::Atom, TAG_AUTHOR, tag)) { + if (!myFeed.isNull()) { + myFeed->authors().push_back(myAuthor); + } + myAuthor.reset(); + myState = FEED; + } + break; + case FA_NAME: + if (testTag(ZLXMLNamespace::Atom, TAG_NAME, tag)) { + myAuthor->setName(myBuffer); + myState = F_AUTHOR; + } + break; + case FEA_NAME: + if (testTag(ZLXMLNamespace::Atom, TAG_NAME, tag)) { + myAuthor->setName(myBuffer); + myState = FE_AUTHOR; + } + break; + case FEL_PRICE: + if (testTag(ZLXMLNamespace::Opds, TAG_PRICE, tag)) { + myLink->setUserData(KEY_PRICE, myBuffer); + myState = FE_LINK; + } + break; + case FEL_FORMAT: + if (testTag(ZLXMLNamespace::DublinCoreTerms, DC_TAG_FORMAT, tag)) { + myLink->setUserData(KEY_FORMAT, myBuffer); + myState = FE_LINK; + } + break; + case FA_URI: + if (testTag(ZLXMLNamespace::Atom, TAG_URI, tag)) { + myAuthor->setUri(myBuffer); + myState = F_AUTHOR; + } + break; + case FEA_URI: + if (testTag(ZLXMLNamespace::Atom, TAG_URI, tag)) { + myAuthor->setUri(myBuffer); + myState = FE_AUTHOR; + } + break; + case FA_EMAIL: + if (testTag(ZLXMLNamespace::Atom, TAG_EMAIL, tag)) { + myAuthor->setEmail(myBuffer); + myState = F_AUTHOR; + } + break; + case FEA_EMAIL: + if (testTag(ZLXMLNamespace::Atom, TAG_EMAIL, tag)) { + myAuthor->setEmail(myBuffer); + myState = FE_AUTHOR; + } + break; + case FE_AUTHOR: + if (testTag(ZLXMLNamespace::Atom, TAG_AUTHOR, tag)) { + myEntry->authors().push_back(myAuthor); + myAuthor.reset(); + myState = F_ENTRY; + } + break; + case FE_ICON: + if (testTag(ZLXMLNamespace::Atom, TAG_ICON, tag)) { + myIcon->setUri(myBuffer); + if (!myEntry.isNull()) { + myEntry->setIcon(myIcon); + } + myIcon.reset(); + myState = F_ENTRY; + } + break; + case FE_ID: + if (testTag(ZLXMLNamespace::Atom, TAG_ID, tag)) { + // FIXME:uri can be lost:buffer will be truncated, if there are extension tags inside the <id> tag + myId->setUri(myBuffer); + myEntry->setId(myId); + myId.reset(); + myState = F_ENTRY; + } + break; + case FE_CATEGORY: + if (testTag(ZLXMLNamespace::Atom, TAG_CATEGORY, tag)) { + myEntry->categories().push_back(myCategory); + myCategory.reset(); + myState = F_ENTRY; + } + break; + case FE_LINK: + if (testTag(ZLXMLNamespace::Atom, TAG_LINK, tag)) { + myEntry->links().push_back(myLink); + myLink.reset(); + myState = F_ENTRY; + } + break; + case FE_PUBLISHED: + if (testTag(ZLXMLNamespace::Atom, TAG_PUBLISHED, tag)) { + // FIXME:uri can be lost:buffer will be truncated, if there are extension tags inside the <id> tag + ATOMDateConstruct::parse(myBuffer, *myPublished); + myEntry->setPublished(myPublished); + myPublished.reset(); + myState = F_ENTRY; + } + break; + case FE_SUMMARY: + if (testTag(ZLXMLNamespace::Atom, TAG_SUMMARY, tag)) { + // FIXME:summary can be lost:buffer will be truncated, if there are extension tags inside the <summary> tag + // TODO:implement ATOMTextConstruct & ATOMSummary + myEntry->setSummary(myBuffer); + mySummaryTagFound = true; + myState = F_ENTRY; + } + break; + case FE_CONTENT: + if (testTag(ZLXMLNamespace::Atom, TAG_CONTENT, tag)) { + // TODO:check this accurately + if (!mySummaryTagFound) { + myEntry->setSummary(myBuffer); + } + myState = F_ENTRY; + } + break; + case FEC_HACK_SPAN: + myEntry->setUserData(KEY_PRICE, myBuffer); + myState = FE_CONTENT; + break; + case FE_SUBTITLE: + if (testTag(ZLXMLNamespace::Atom, TAG_SUBTITLE, tag)) { + // TODO:check this accurately + if (!mySummaryTagFound) { + myEntry->setSummary(myBuffer); + } + myState = F_ENTRY; + } + break; + case FE_TITLE: + if (testTag(ZLXMLNamespace::Atom, TAG_TITLE, tag)) { + // FIXME:title can be lost:buffer will be truncated, if there are extension tags inside the <title> tag + // TODO:implement ATOMTextConstruct & ATOMTitle + myEntry->setTitle(myBuffer); + myState = F_ENTRY; + } else { + // TODO: remove this temporary code + // DON'T clear myBuffer + return; + } + break; + case FE_UPDATED: + if (testTag(ZLXMLNamespace::Atom, TAG_UPDATED, tag)) { + // FIXME:uri can be lost:buffer will be truncated, if there are extension tags inside the <id> tag + ATOMDateConstruct::parse(myBuffer, *myUpdated); + myEntry->setUpdated(myUpdated); + myUpdated.reset(); + myState = F_ENTRY; + } + break; + case FE_DC_LANGUAGE: + if (testTag(ZLXMLNamespace::DublinCoreTerms, DC_TAG_LANGUAGE, tag)) { + // FIXME:language can be lost:buffer will be truncated, if there are extension tags inside the <dc:language> tag + myEntry->setDCLanguage(myBuffer); + myState = F_ENTRY; + } + break; + case FE_DC_ISSUED: + if (testTag(ZLXMLNamespace::DublinCoreTerms, DC_TAG_ISSUED, tag)) { + // FIXME:issued can be lost:buffer will be truncated, if there are extension tags inside the <dc:issued> tag + DCDate *issued = new DCDate(); + ATOMDateConstruct::parse(myBuffer, *issued); + myEntry->setDCIssued(issued); + myState = F_ENTRY; + } + break; + case FE_DC_PUBLISHER: + if (testTag(ZLXMLNamespace::DublinCoreTerms, DC_TAG_PUBLISHER, tag)) { + // FIXME:publisher can be lost:buffer will be truncated, if there are extension tags inside the <dc:publisher> tag + myEntry->setDCPublisher(myBuffer); + myState = F_ENTRY; + } + break; + case FE_CALIBRE_SERIES: + if (testTag(ZLXMLNamespace::CalibreMetadata, CALIBRE_TAG_SERIES, tag)) { + myEntry->setSeriesTitle(myBuffer); + myState = F_ENTRY; + } + break; + case FE_CALIBRE_SERIES_INDEX: + if (testTag(ZLXMLNamespace::CalibreMetadata, CALIBRE_TAG_SERIES_INDEX, tag)) { + myEntry->setSeriesIndex(std::atoi(myBuffer.c_str())); + myState = F_ENTRY; + } + break; + case OPENSEARCH_TOTALRESULTS: + if (testTag(ZLXMLNamespace::OpenSearch, OPENSEARCH_TAG_TOTALRESULTS, tag)) { + int number = std::atoi(myBuffer.c_str()); + if (!myFeed.isNull()) { + myFeed->setOpensearchTotalResults(number); + } + myState = FEED; + } + break; + case OPENSEARCH_ITEMSPERPAGE: + if (testTag(ZLXMLNamespace::OpenSearch, OPENSEARCH_TAG_ITEMSPERPAGE, tag)) { + int number = std::atoi(myBuffer.c_str()); + if (!myFeed.isNull()) { + myFeed->setOpensearchItemsPerPage(number); + } + myState = FEED; + } + break; + case OPENSEARCH_STARTINDEX: + if (testTag(ZLXMLNamespace::OpenSearch, OPENSEARCH_TAG_STARTINDEX, tag)) { + int number = std::atoi(myBuffer.c_str()); + if (!myFeed.isNull()) { + myFeed->setOpensearchStartIndex(number); + } + myState = FEED; + } + break; + } + + myBuffer.clear(); +} + +void OPDSXMLParser::characterDataHandler(const char *data, std::size_t len) { + myBuffer.append(data, len); +} diff --git a/fbreader/src/network/opds/OPDSXMLParser.h b/fbreader/src/network/opds/OPDSXMLParser.h new file mode 100644 index 0000000..82f0124 --- /dev/null +++ b/fbreader/src/network/opds/OPDSXMLParser.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __OPDSXMLPARSER_H__ +#define __OPDSXMLPARSER_H__ + +#include <ZLXMLReader.h> + +#include "OPDSMetadata.h" +#include "OPDSFeedReader.h" + + +class OPDSXMLParser : public ZLXMLReader { + +public: + static const std::string KEY_PRICE; + static const std::string KEY_CURRENCY; + static const std::string KEY_FORMAT; + +public: + OPDSXMLParser(shared_ptr<OPDSFeedReader> feedReader, bool readEntryNotFeed = false); + +protected: + void startElementHandler(const char *tag, const char **attributes); + void endElementHandler(const char *tag); + void characterDataHandler(const char *text, std::size_t len); + bool processNamespaces() const; + +protected: + enum State { + START, + FEED, F_ENTRY, F_ID, F_LINK, F_CATEGORY, F_TITLE, F_UPDATED, F_AUTHOR, F_SUBTITLE, F_ICON, F_SUMMARY, + FA_NAME, FA_URI, FA_EMAIL, + FE_AUTHOR, FE_ID, FE_CATEGORY, FE_LINK, FE_PUBLISHED, FE_SUMMARY, FE_CONTENT, FE_SUBTITLE, FE_TITLE, FE_ICON, FE_UPDATED, FE_DC_LANGUAGE, FE_DC_ISSUED, FE_DC_PUBLISHER, FE_CALIBRE_SERIES, FE_CALIBRE_SERIES_INDEX, + FEL_PRICE, FEL_FORMAT, + FEA_NAME, FEA_URI, FEA_EMAIL, + OPENSEARCH_TOTALRESULTS, OPENSEARCH_ITEMSPERPAGE, OPENSEARCH_STARTINDEX, + FEC_HACK_SPAN, + }; + +protected: + shared_ptr<OPDSFeedReader> myFeedReader; + State myState; + +private: + std::string myBuffer; + shared_ptr<OPDSFeedMetadata> myFeed; + shared_ptr<OPDSEntry> myEntry; + + shared_ptr<ATOMAuthor> myAuthor; + shared_ptr<ATOMId> myId; + shared_ptr<ATOMIcon> myIcon; + shared_ptr<ATOMLink> myLink; + shared_ptr<ATOMCategory> myCategory; + shared_ptr<ATOMUpdated> myUpdated; + shared_ptr<ATOMPublished> myPublished; + + //shared_ptr<ATOMTitle> myTitle; // TODO: implement ATOMTextConstruct & ATOMTitle + //shared_ptr<ATOMSummary> mySummary; // TODO: implement ATOMTextConstruct & ATOMSummary + bool mySummaryTagFound; +}; + +#endif /* __OPDSXMLPARSER_H__ */ diff --git a/fbreader/src/network/opds/OpenSearchXMLReader.cpp b/fbreader/src/network/opds/OpenSearchXMLReader.cpp new file mode 100644 index 0000000..686d8c1 --- /dev/null +++ b/fbreader/src/network/opds/OpenSearchXMLReader.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <[email protected]> + * + * 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 "OpenSearchXMLReader.h" +#include <ZLMimeType.h> + +static const std::string TAG_URL = "Url"; + +std::string OpenSearchXMLReader::convertOpenSearchURL(const std::string& raws) { //TODO + std::size_t pos = raws.find('{'); + return raws.substr(0, pos) + "%s"; +} + +void OpenSearchXMLReader::startElementHandler(const char *tag, const char **attributes) { + if (TAG_URL == tag) { + const char *type = attributeValue(attributes, "type"); + if (ZLMimeType::get(type)->weakEquals(*ZLMimeType::APPLICATION_ATOM_XML)) { + const char *templ = attributeValue(attributes, "template"); + if (templ != 0) { + myTemplateURL = convertOpenSearchURL(templ); + } + } + } +} + +void OpenSearchXMLReader::endElementHandler(const char *tag) { + (void)tag; +} + +void OpenSearchXMLReader::characterDataHandler(const char *text, std::size_t len) { + (void)text; + (void)len; +} diff --git a/fbreader/src/network/opds/OpenSearchXMLReader.h b/fbreader/src/network/opds/OpenSearchXMLReader.h new file mode 100644 index 0000000..2b53f19 --- /dev/null +++ b/fbreader/src/network/opds/OpenSearchXMLReader.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2008-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __OPENSEARCHXMLREADER_H__ +#define __OPENSEARCHXMLREADER_H__ + +#include <string> +#include <ZLXMLReader.h> + +class OpenSearchXMLReader : public ZLXMLReader { + +public: + OpenSearchXMLReader() {} + std::string templateURL() {return myTemplateURL;} + + static std::string convertOpenSearchURL(const std::string& raws); + +private: + void startElementHandler(const char *tag, const char **attributes); + void endElementHandler(const char *tag); + void characterDataHandler(const char *text, std::size_t len); + std::string myTemplateURL; + +}; + +#endif /* __OPENSEARCHXMLREADER_H__ */ diff --git a/fbreader/src/network/opds/URLRewritingRule.cpp b/fbreader/src/network/opds/URLRewritingRule.cpp new file mode 100644 index 0000000..8cea851 --- /dev/null +++ b/fbreader/src/network/opds/URLRewritingRule.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2010-2012 Geometer Plus <[email protected]> + * + * 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 "URLRewritingRule.h" + +URLRewritingRule::URLRewritingRule(const std::map<std::string,std::string> &map) : myType(UNKNOWN), myApply(ALWAYS) { + for (std::map<std::string, std::string>::const_iterator it = map.begin(); it != map.end(); ++it) { + std::string key = (*it).first; + std::string value = (*it).second; + + if (key == "type") { + if (value == "addUrlParameter") { + myType = ADD_URL_PARAMETER; + } else if (value == "rewrite") { + myType = REWRITE; + } + } else if (key == "apply") { + if (value == "internal") { + myApply = INTERNAL; + } else if (value == "external") { + myApply = EXTERNAL; + } + } else { + myParameters.insert(std::make_pair(key, value)); + } + + } +} + +std::string URLRewritingRule::apply(const std::string &url) const { + std::string appliedUrl = url; + switch (myType) { + case ADD_URL_PARAMETER: + { + std::string name, value; + std::map<std::string, std::string>::const_iterator it; + it = myParameters.find("name"); + if (it != myParameters.end()) { + name = (*it).second; + } + it = myParameters.find("value"); + if (it != myParameters.end()) { + value = (*it).second; + } + if (name.empty() || value.empty()) { + break; + } + ZLNetworkUtil::appendParameter(appliedUrl, name, value); + } + case REWRITE: //TODO implement (regular expressions should be used here) + default: + break; + } + return appliedUrl; +} + +URLRewritingRule::RuleApply URLRewritingRule::whereToApply() const { + return myApply; +} diff --git a/fbreader/src/network/opds/URLRewritingRule.h b/fbreader/src/network/opds/URLRewritingRule.h new file mode 100644 index 0000000..1251139 --- /dev/null +++ b/fbreader/src/network/opds/URLRewritingRule.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2010-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __URLREWRITINGRULE_H__ +#define __URLREWRITINGRULE_H__ + +#include <string> +#include <map> + +class URLRewritingRule { + +public: + enum RuleType { + ADD_URL_PARAMETER, + REWRITE, + UNKNOWN, + }; + + enum RuleApply { + ALWAYS, EXTERNAL, INTERNAL + }; + + URLRewritingRule(const std::map<std::string,std::string> &attributesMap); + std::string apply(const std::string &url) const; + RuleApply whereToApply() const; + +private: + RuleType myType; + RuleApply myApply; + std::map<std::string, std::string> myParameters; +}; + + +#endif /* __URLREWRITINGRULE_H__ */ diff --git a/fbreader/src/network/tree/NetworkAuthorTree.cpp b/fbreader/src/network/tree/NetworkAuthorTree.cpp new file mode 100644 index 0000000..8106838 --- /dev/null +++ b/fbreader/src/network/tree/NetworkAuthorTree.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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 <ZLResource.h> +#include <ZLImage.h> + +#include "NetworkTreeNodes.h" + +const ZLTypeId NetworkAuthorTree::TYPE_ID(NetworkTree::TYPE_ID); + +const ZLTypeId &NetworkAuthorTree::typeId() const { + return TYPE_ID; +} + +const ZLResource &NetworkAuthorTree::resource() const { + return ZLResource::resource("networkView")["authorNode"]; +} + +NetworkAuthorTree::NetworkAuthorTree(NetworkTree *parent, const NetworkBookItem::AuthorData &author) : NetworkTree(parent), myAuthor(author) { + init(); +} + +void NetworkAuthorTree::init() { + //registerExpandTreeAction(); +} + +std::string NetworkAuthorTree::title() const { + return myAuthor.DisplayName; +} + +shared_ptr<const ZLImage> NetworkAuthorTree::image() const { + return defaultCoverImage("booktree-author.png"); +} + +const NetworkBookItem::AuthorData &NetworkAuthorTree::author() { + return myAuthor; +} diff --git a/fbreader/src/network/tree/NetworkBookTree.cpp b/fbreader/src/network/tree/NetworkBookTree.cpp new file mode 100644 index 0000000..c59d247 --- /dev/null +++ b/fbreader/src/network/tree/NetworkBookTree.cpp @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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 <ZLResource.h> +#include <ZLImage.h> +#include <ZLExecutionUtil.h> +#include <ZLNetworkManager.h> + +#include "NetworkTreeNodes.h" +#include "NetworkTreeFactory.h" +#include "NetworkLibrary.h" +#include "NetworkCatalogUtil.h" + +#include "../../networkActions/NetworkActions.h" + +const ZLTypeId NetworkBookTree::TYPE_ID(ZLTreePageNode::TYPE_ID); + +const ZLTypeId &NetworkBookTree::typeId() const { + return TYPE_ID; +} + +const ZLResource &NetworkBookTree::resource() const { + return ZLResource::resource("networkView")["bookNode"]; +} + +NetworkBookTree::NetworkBookTree(NetworkTree *parent, shared_ptr<NetworkItem> book, SummaryType summaryType) : ZLTreePageNode(parent), myBook(book), mySummaryType(summaryType) { + init(); +} + +//TODO we don't need a actions wrappers since we don't use old network library +class NetworkTreeBookReadAction : public NetworkBookReadAction { +public: + NetworkTreeBookReadAction(const NetworkBookTree &tree, const NetworkBookItem &book, bool demo) : NetworkBookReadAction(book, demo), myTree(tree) {} + void run() { + NetworkBookReadAction::run(); + myTree.close(); + } + +private: + const NetworkBookTree &myTree; +}; + +static std::vector<shared_ptr<ZLTreeAction> > getBookActions(NetworkBookTree &tree) { + std::vector<shared_ptr<ZLTreeAction> > actions; + const NetworkBookItem &book = tree.book(); + if (!book.reference(BookReference::DOWNLOAD_FULL).isNull() || + !book.reference(BookReference::DOWNLOAD_FULL_CONDITIONAL).isNull()) { + actions.push_back(new NetworkTreeBookReadAction(tree, book, false)); + actions.push_back(new NetworkBookDownloadAction(tree, book, false)); + actions.push_back(new NetworkBookDeleteAction(book)); + } + if (!book.reference(BookReference::DOWNLOAD_DEMO).isNull()) { + actions.push_back(new NetworkTreeBookReadAction(tree, book, true)); + actions.push_back(new NetworkBookDownloadAction(tree, book, true, tree.resource()["demo"].value())); + } + if (!book.reference(BookReference::BUY).isNull()) { + actions.push_back(new NetworkBookBuyDirectlyAction(tree, book)); + } else if (!book.reference(BookReference::BUY_IN_BROWSER).isNull()) { + actions.push_back(new NetworkBookBuyInBrowserAction(book)); + } + return actions; +} + +void NetworkBookTree::init() { + std::vector<shared_ptr<ZLTreeAction> > actions = getBookActions(*this); + for (std::size_t i = 0; i < actions.size(); ++i) { + registerAction(actions.at(i)); + } +} + +std::string NetworkBookTree::title() const { + return myBook->Title; +} + +std::string NetworkBookTree::subtitle() const { + int count = 0; + std::string authorsString; + const std::vector<NetworkBookItem::AuthorData> authors = book().Authors; + for (std::vector<NetworkBookItem::AuthorData>::const_iterator it = authors.begin(); it != authors.end(); ++it) { + if (!authorsString.empty()) { + authorsString += ", "; + } + authorsString += it->DisplayName; + ++count; + } + if (mySummaryType == NONE && count == 1) { + return std::string(); + } + return authorsString; +} + +shared_ptr<ZLTreePageInfo> NetworkBookTree::getPageInfo() /*const*/ { + if (myPageInfo.isNull()) { + myPageInfo = new BookItemWrapper(*this, myBook); + } + return myPageInfo; +} + + +shared_ptr<const ZLImage> NetworkBookTree::image() const { + if (myImage.isNull()) { + myImage = NetworkCatalogUtil::getAndDownloadImageByUrl(myBook->URLByType[NetworkItem::URL_COVER], this); + } + return (!myImage.isNull() && myImage->good()) ? myImage : FBTree::defaultCoverImage("booktree-book.png"); +} + +shared_ptr<const ZLImage> NetworkBookTree::fullImage() const { + if (myBook->URLByType.find(NetworkItem::URL_FULL_COVER) == myBook->URLByType.end()) { + return 0; + } + shared_ptr<const ZLImage> fullImage = NetworkCatalogUtil::getImageByUrl(myBook->URLByType[NetworkItem::URL_FULL_COVER]); + return !fullImage.isNull() ? fullImage : 0; +} + +const NetworkBookItem &NetworkBookTree::book() const { + return (const NetworkBookItem&)*myBook; +} + + +NetworkBookTree::BookItemWrapper::BookItemWrapper(NetworkBookTree &tree, shared_ptr<NetworkItem> bookItem) : + myTree(tree), myBookItem(bookItem), myIsInitialized(false) { +} + +bool NetworkBookTree::BookItemWrapper::isPageInfoLoaded() { + return myIsInitialized; +} + +class BookItemWrapperScope : public ZLUserData { +public: + shared_ptr<ZLNetworkRequest::Listener> listener; +}; + +void NetworkBookTree::BookItemWrapper::loadAll(shared_ptr<ZLNetworkRequest::Listener> listener) { + if (myIsInitialized) { + listener->finished(); + return; + } + + NetworkBookItem &bookItem = book(); + + BookItemWrapperScope *scope = new BookItemWrapperScope; + scope->listener = listener; + shared_ptr<ZLUserDataHolder> scopeData = new ZLUserDataHolder; + scopeData->addUserData("scope", scope); + + if (bookItem.isFullyLoaded()) { + onInformationLoaded(*scopeData, std::string()); + return; + } + bookItem.loadFullInformation(ZLExecutionUtil::createListener(scopeData, this, &NetworkBookTree::BookItemWrapper::onInformationLoaded)); +} + +void NetworkBookTree::BookItemWrapper::onInformationLoaded(ZLUserDataHolder &data, const std::string &error){ + shared_ptr<const ZLImage> cover = image(); + if (!cover.isNull()) { + shared_ptr<ZLNetworkRequest> request = cover->synchronizationData(); + if (!request.isNull()) { + request->setListener(ZLExecutionUtil::createListener(new ZLUserDataHolder(data), this, &NetworkBookTree::BookItemWrapper::onCoverLoaded)); + ZLNetworkManager::Instance().performAsync(request); + return; + } + } + onCoverLoaded(data, error); //if image is loaded already +} + +void NetworkBookTree::BookItemWrapper::onCoverLoaded(ZLUserDataHolder &data, const std::string &error) { + BookItemWrapperScope &scope = static_cast<BookItemWrapperScope&>(*data.getUserData("scope")); + if (error.empty()) { + myIsInitialized = true; + } + scope.listener->finished(error); +} + +std::string NetworkBookTree::BookItemWrapper::title() const { + return book().Title; +} + +std::vector<std::string> NetworkBookTree::BookItemWrapper::authors() const { + const NetworkBookItem &bookItem = book(); + std::vector<std::string> authors; + for (std::size_t i = 0; i < bookItem.Authors.size(); ++i) { + authors.push_back(bookItem.Authors.at(i).DisplayName); + } + return authors; +} + +std::vector<std::string> NetworkBookTree::BookItemWrapper::tags() const { + return book().Tags; +} + +std::string NetworkBookTree::BookItemWrapper::summary() const { + return book().Summary; +} + +shared_ptr<const ZLImage> NetworkBookTree::BookItemWrapper::image() const { + shared_ptr<const ZLImage> fullImage = myTree.fullImage(); + if (!fullImage.isNull()) { + return fullImage; + } + return myTree.image(); +} + +const std::vector<shared_ptr<ZLTreeAction> > &NetworkBookTree::BookItemWrapper::actions() const { + return myTree.actions(); +} + +std::string NetworkBookTree::BookItemWrapper::actionText(const shared_ptr<ZLTreeAction> &action) const { + return myTree.actionText(action); +} + +class RelatedAction : public ZLTreeAction { +public: + RelatedAction(shared_ptr<NetworkItem> item) : myTitle(item->Title) { + myNode = new NetworkCatalogTree(&NetworkLibrary::Instance().getFakeCatalogTree(), item); + //myNode = NetworkTreeFactory::createNetworkTree(0, item); + } + ZLResourceKey key() const { return ZLResourceKey(""); } + std::string text(const ZLResource &/*resource*/) const { + return myTitle; + } + void run() { + if (NetworkCatalogTree *tree = zlobject_cast<NetworkCatalogTree*>(&*myNode)){ + tree->expand(); + } + } + +private: + shared_ptr<ZLTreeTitledNode> myNode; + std::string myTitle; +}; + +const std::vector<shared_ptr<ZLTreeAction> > NetworkBookTree::BookItemWrapper::relatedActions() const { + if (!myRelatedActions.empty()) { + return myRelatedActions; + } + std::vector<shared_ptr<NetworkItem> > catalogItems = static_cast<NetworkBookItem&>(*myBookItem).getRelatedCatalogsItems(); + for (std::size_t i = 0; i < catalogItems.size(); ++i) { + shared_ptr<NetworkItem> item = catalogItems.at(i); + myRelatedActions.push_back(new RelatedAction(item)); + } + return myRelatedActions; +} + +NetworkBookItem &NetworkBookTree::BookItemWrapper::book() const { + return (NetworkBookItem&)*myBookItem; +} diff --git a/fbreader/src/network/tree/NetworkCatalogRootTree.cpp b/fbreader/src/network/tree/NetworkCatalogRootTree.cpp new file mode 100644 index 0000000..50a78f5 --- /dev/null +++ b/fbreader/src/network/tree/NetworkCatalogRootTree.cpp @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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 <ZLStringUtil.h> +#include <ZLExecutionUtil.h> + +#include "../../fbreader/FBReader.h" + +#include "../authentication/NetworkAuthenticationManager.h" +#include "../../networkActions/NetworkOperationRunnable.h" +#include "../../networkActions/AuthenticationDialogManager.h" +#include "../../networkActions/PasswordRecoveryDialog.h" +#include "../../networkActions/RegisterUserDialog.h" + +#include "NetworkLibrary.h" + +#include "NetworkTreeNodes.h" + +class NetworkTreeCatalogAuthAction : public ZLTreeAction { + +protected: + NetworkTreeCatalogAuthAction(NetworkAuthenticationManager &mgr, bool forLoggedUsers); + +protected: + bool makesSense() const; + +protected: + NetworkAuthenticationManager &myManager; + +private: + const bool myForLoggedUsers; +}; + +class NetworkCatalogRootTree::LoginAction : public NetworkTreeCatalogAuthAction { + +public: + LoginAction(NetworkAuthenticationManager &mgr, ZLTreeNode *node); + void run(); + ZLResourceKey key() const; + +private: + void onAuthorised(const std::string &error); + +private: + ZLTreeNode *myNode; + +friend class LoginActionListener; +}; + +class NetworkCatalogRootTree::LogoutAction : public NetworkTreeCatalogAuthAction { + +public: + LogoutAction(NetworkAuthenticationManager &mgr); + void run(); + ZLResourceKey key() const; + std::string text(const ZLResource &resource) const; +}; + +class NetworkCatalogRootTree::TopupAccountAction : public NetworkTreeCatalogAuthAction { + +public: + TopupAccountAction(NetworkAuthenticationManager &mgr); + +private: + void run(); + ZLResourceKey key() const; + std::string text(const ZLResource &resource) const; + bool makesSense() const; +}; + +class NetworkCatalogRootTree::PasswordRecoveryAction : public NetworkTreeCatalogAuthAction { + +public: + PasswordRecoveryAction(NetworkAuthenticationManager &mgr); + void run(); + ZLResourceKey key() const; +}; + +class NetworkCatalogRootTree::RegisterUserAction : public NetworkTreeCatalogAuthAction { + +public: + RegisterUserAction(NetworkAuthenticationManager &mgr); + void run(); + ZLResourceKey key() const; +}; + +const ZLTypeId NetworkCatalogRootTree::TYPE_ID(NetworkCatalogTree::TYPE_ID); + +const ZLTypeId &NetworkCatalogRootTree::typeId() const { + return TYPE_ID; +} + +NetworkCatalogRootTree::NetworkCatalogRootTree(RootTree *parent, NetworkLink &link, std::size_t position) : + NetworkCatalogTree(parent, link.libraryItem(), position), myLink(link) { + init(); //at old version, init is called when node should be painted (and if initialized yet) +} + +void NetworkCatalogRootTree::init() { + shared_ptr<NetworkAuthenticationManager> mgr = myLink.authenticationManager(); + //registerAction(new ExpandCatalogAction(*this)); + //registerAction(new ReloadAction(*this)); + if (!mgr.isNull()) { + registerAction(new LoginAction(*mgr, this)); + registerAction(new LogoutAction(*mgr)); + registerAction(new TopupAccountAction(*mgr)); + + if (mgr->registrationSupported()) { + registerAction(new RegisterUserAction(*mgr)); + } + if (mgr->passwordRecoverySupported()) { + registerAction(new PasswordRecoveryAction(*mgr)); + } + } +} + +const ZLResource &NetworkCatalogRootTree::resource() const { + return ZLResource::resource("networkView")["libraryItemRootNode"]; +} + +NetworkTreeCatalogAuthAction::NetworkTreeCatalogAuthAction(NetworkAuthenticationManager &mgr, bool forLoggedUsers) : myManager(mgr), myForLoggedUsers(forLoggedUsers) { +} + +bool NetworkTreeCatalogAuthAction::makesSense() const { + return (myManager.isAuthorised().Status == B3_FALSE) != myForLoggedUsers; +} + +NetworkCatalogRootTree::LoginAction::LoginAction(NetworkAuthenticationManager &mgr, ZLTreeNode *node) : + NetworkTreeCatalogAuthAction(mgr, false), myNode(node) { +} + +ZLResourceKey NetworkCatalogRootTree::LoginAction::key() const { + return ZLResourceKey("login"); +} + +class LoginActionListener : public ZLNetworkRequest::Listener { +public: + LoginActionListener(NetworkCatalogRootTree::LoginAction &action) : myAction(action) {} + + virtual void finished(const std::string &error) { + myAction.onAuthorised(error); + } + + virtual void setUIStatus(bool enabled) { + if (enabled) { + myAction.myNode->notifyDownloadStarted(); + } else { + myAction.myNode->notifyDownloadStopped(); + } + } + +private: + NetworkCatalogRootTree::LoginAction &myAction; +}; + +void NetworkCatalogRootTree::LoginAction::run() { + if (!NetworkOperationRunnable::tryConnect()) { + return; + } + AuthenticationDialogManager::authAndInitAsync( + myManager, + new LoginActionListener(*this) + ); +} + +void NetworkCatalogRootTree::LoginAction::onAuthorised(const std::string &/*error*/) { + myNode->notifyDownloadStopped(); + NetworkLibrary::Instance().invalidateVisibility(); + NetworkLibrary::Instance().synchronize(); + NetworkLibrary::Instance().refresh(); +} + +NetworkCatalogRootTree::LogoutAction::LogoutAction(NetworkAuthenticationManager &mgr) : NetworkTreeCatalogAuthAction(mgr, true) { +} + +ZLResourceKey NetworkCatalogRootTree::LogoutAction::key() const { + return ZLResourceKey("logout"); +} + +std::string NetworkCatalogRootTree::LogoutAction::text(const ZLResource &resource) const { + const std::string text = ZLTreeAction::text(resource); + return ZLStringUtil::printf(text, myManager.currentUserName()); +} + +void NetworkCatalogRootTree::LogoutAction::run() { + myManager.logOut(); + NetworkLibrary::Instance().invalidateVisibility(); + NetworkLibrary::Instance().synchronize(); + NetworkLibrary::Instance().refresh(); +} + + +NetworkCatalogRootTree::TopupAccountAction::TopupAccountAction(NetworkAuthenticationManager &mgr) : NetworkTreeCatalogAuthAction(mgr, true) { +} + +ZLResourceKey NetworkCatalogRootTree::TopupAccountAction::key() const { + return !myManager.currentAccount().empty() ? ZLResourceKey("topupAccount") : ZLResourceKey("topupAccountUndefined"); +} + +std::string NetworkCatalogRootTree::TopupAccountAction::text(const ZLResource &resource) const { + const std::string text = ZLTreeAction::text(resource); + std::string account = myManager.currentAccount(); + if (!account.empty() && !myManager.topupAccountLink().empty()) { + return ZLStringUtil::printf(text, account); + } + return text; +} + +void NetworkCatalogRootTree::TopupAccountAction::run() { + FBReader::Instance().openLinkInBrowser(myManager.topupAccountLink()); + NetworkLibrary::Instance().refresh(); +} + +bool NetworkCatalogRootTree::TopupAccountAction::makesSense() const { + return NetworkTreeCatalogAuthAction::makesSense(); +} + +NetworkCatalogRootTree::PasswordRecoveryAction::PasswordRecoveryAction(NetworkAuthenticationManager &mgr) : NetworkTreeCatalogAuthAction(mgr, false) { +} + +ZLResourceKey NetworkCatalogRootTree::PasswordRecoveryAction::key() const { + return ZLResourceKey("passwordRecovery"); +} + +void NetworkCatalogRootTree::PasswordRecoveryAction::run() { + if (!NetworkOperationRunnable::tryConnect()) { + return; + } + + PasswordRecoveryDialog::run(myManager); + FBReader::Instance().refreshWindow(); + NetworkLibrary::Instance().refresh(); +} + +NetworkCatalogRootTree::RegisterUserAction::RegisterUserAction(NetworkAuthenticationManager &mgr) : NetworkTreeCatalogAuthAction(mgr, false) { +} + +ZLResourceKey NetworkCatalogRootTree::RegisterUserAction::key() const { + return ZLResourceKey("register"); +} + +void NetworkCatalogRootTree::RegisterUserAction::run() { + if (!NetworkOperationRunnable::tryConnect()) { + return; + } + + RegisterUserDialog::run(myManager); + FBReader::Instance().refreshWindow(); + NetworkLibrary::Instance().refresh(); +} diff --git a/fbreader/src/network/tree/NetworkCatalogTree.cpp b/fbreader/src/network/tree/NetworkCatalogTree.cpp new file mode 100644 index 0000000..6b6bf6e --- /dev/null +++ b/fbreader/src/network/tree/NetworkCatalogTree.cpp @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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 <algorithm> + +#include <ZLDialogManager.h> + +#include "../authentication/NetworkAuthenticationManager.h" +#include "NetworkCatalogUtil.h" +#include "../../networkActions/NetworkOperationRunnable.h" +#include "../NetworkErrors.h" +#include "NetworkTreeFactory.h" +#include "../../networkActions/AuthenticationDialogManager.h" +#include "NetworkTreeNodes.h" + +const ZLTypeId NetworkCatalogTree::TYPE_ID(NetworkTree::TYPE_ID); + +const ZLTypeId &NetworkCatalogTree::typeId() const { + return TYPE_ID; +} + +NetworkCatalogTree::NetworkCatalogTree(RootTree *parent, shared_ptr<NetworkItem> item, std::size_t position) : + NetworkTree(parent, position), myItem(item) { +} + +NetworkCatalogTree::NetworkCatalogTree(NetworkCatalogTree *parent, shared_ptr<NetworkItem> item, std::size_t position) : + NetworkTree(parent, position), myItem(item) { + init(); +} + +void NetworkCatalogTree::init() { +// if (!item().URLByType[NetworkItem::URL_CATALOG].empty()) { +// registerAction(new ExpandCatalogAction(*this)); +// } +// const std::string htmlUrl = +// item().URLByType[NetworkItem::URL_HTML_PAGE]; +// if (!htmlUrl.empty()) { +// registerAction(new OpenInBrowserAction(htmlUrl)); +// } + //registerAction(new ReloadAction(*this)); +} + +std::string NetworkCatalogTree::title() const { + return myItem->Title; +} + +std::string NetworkCatalogTree::subtitle() const { + return ((const NetworkCatalogItem&)*myItem).Summary; +} + + +shared_ptr<const ZLImage> NetworkCatalogTree::image() const { + const std::string &url = myItem->URLByType[NetworkItem::URL_COVER]; + if (url.empty()) { + if (ZLTreeTitledNode* node = zlobject_cast<ZLTreeTitledNode*>(parent())) { + return node->image(); + } + } + if (myImage.isNull()) { + myImage = NetworkCatalogUtil::getAndDownloadImageByUrl(url, this); + } + return (!myImage.isNull() && myImage->good()) ? myImage : FBTree::defaultCoverImage("booktree-catalog.png"); +} + +class AsyncLoadSubCatalogRunnable : public ZLNetworkRequest::Listener { + +public: + AsyncLoadSubCatalogRunnable(NetworkCatalogTree *tree, bool resumeMode) : + myTree(tree), myResumeMode(resumeMode) { + myTree->notifyDownloadStarted(); + if (myResumeMode) { + myTree->item().resumeLoading(myChildrens, this); + } else { + myTree->item().loadChildren(myChildrens, this); + } + } + + void finished(const std::string &error) { + myTree->notifyDownloadStopped(); + myTree->onChildrenReceived(myChildrens, error); + } + + void setUIStatus(bool enabled) { + if (enabled) { + myTree->notifyDownloadStarted(); + } else { + myTree->notifyDownloadStopped(); + } + } + +private: + NetworkCatalogTree *myTree; + NetworkItem::List myChildrens; + bool myResumeMode; +}; + +//class NetworkCatalogTreeAuthScope : public ZLUserData { +//public: +// shared_ptr<ZLNetworkRequest::Listener> listener; +//}; + +class NetworkCatalogTreeAuthListener : public ZLNetworkRequest::Listener { +public: + NetworkCatalogTreeAuthListener(NetworkCatalogTree *tree) : myTree(tree) { + } + + void finished(const std::string &error) { + myTree->onAuthCheck(error); + } + + void setUIStatus(bool enabled) { + if (enabled) { + myTree->notifyDownloadStarted(); + } else { + myTree->notifyDownloadStopped(); + } + } + +private: + NetworkCatalogTree *myTree; +}; + +void NetworkCatalogTree::requestChildren(shared_ptr<ZLNetworkRequest::Listener> listener) { + myListeners.push_back(listener); + if (myListeners.size() > 1) { + return; + } + + const NetworkLink &link = item().Link; + shared_ptr<NetworkAuthenticationManager> manager = link.authenticationManager(); + + if (item().getVisibility() == B3_UNDEFINED && !manager.isNull()) { + AuthenticationDialogManager::authAndInitAsync(*manager, new NetworkCatalogTreeAuthListener(this)); + return; + } + + if (!manager.isNull() && manager->isAuthorised(0).Status == B3_TRUE) { + AuthenticationDialogManager::athoriseIfCan(*manager, new NetworkCatalogTreeAuthListener(this)); + return; + } + onAuthCheck(std::string()); +} + +void NetworkCatalogTree::onAuthCheck(const std::string &error) { + if (!error.empty()) { + notifyListeners(error); + return; + } + + if (!myChildrenItems.empty()) { + notifyDownloadStopped(); + notifyListeners(std::string()); //TODO maybe not be silent about auth error here + return; + } + new AsyncLoadSubCatalogRunnable(this, false); + +} + +void NetworkCatalogTree::requestMoreChildren(shared_ptr<ZLNetworkRequest::Listener> listener) { + //TODO does double requesting is processed correct? + if (!item().supportsResumeLoading()) { + listener->finished(); + return; + } + myListeners.push_back(listener); + if (myListeners.size() == 1) { + new AsyncLoadSubCatalogRunnable(this, true); + } +} + +void NetworkCatalogTree::onChildrenReceived(NetworkItem::List &childrens, const std::string &error) { + if (!error.empty()) { + //special case for authenticationFailed after 'cancel' button pressed in AuthDialog? + //TODO maybe it'll be work wrong at some cases? maybe we should have another error this case? + if (error != NetworkErrors::errorMessage(NetworkErrors::ERROR_AUTHENTICATION_FAILED)) { + NetworkErrors::showErrorMessage(error); + } + notifyListeners(error); + return; + } + + myChildrenItems.insert(myChildrenItems.end(), childrens.begin(), childrens.end()); + + if (myChildrenItems.empty()) { + ZLDialogManager::Instance().informationBox(ZLResourceKey("emptyCatalogBox")); + notifyListeners(error); + return; + } + + bool hasSubcatalogs = false; + for (NetworkItem::List::iterator it = myChildrenItems.begin(); it != myChildrenItems.end(); ++it) { + if ((*it)->typeId() == NetworkCatalogItem::TYPE_ID) { + hasSubcatalogs = true; + break; + } + } + + //TODO rewrite this method + if (hasSubcatalogs) { + for (NetworkItem::List::iterator it = childrens.begin(); it != childrens.end(); ++it) { + NetworkTreeFactory::createNetworkTree(this, *it); + } + } else { + NetworkTreeFactory::fillAuthorTree(this, childrens); + } + notifyListeners(error); + + this->updated(); +} + +void NetworkCatalogTree::notifyListeners(const std::string &error) { + for (std::size_t i = 0; i < myListeners.size(); ++i) { + if (!myListeners.at(i).isNull()) + myListeners.at(i)->finished(error); + } + myListeners.clear(); +} + +NetworkCatalogItem &NetworkCatalogTree::item() { + return (NetworkCatalogItem&)*myItem; +} + +void NetworkCatalogTree::updateVisibility() { + //adding to remove list and clearing all existed nodes + List toRemove; + NetworkItem::List itemsWithNodes; //used in loop for creating new nodes (for these items new nodes won't be created) + for (size_t i = 0; i < children().size(); ++i) { + ZLTreeNode* tree = children().at(i); + if (!tree->isInstanceOf(NetworkCatalogTree::TYPE_ID)) { + continue; + } + NetworkCatalogTree *child = (NetworkCatalogTree*)tree; + itemsWithNodes.push_back(child->myItem); + switch (child->item().getVisibility()) { + case B3_TRUE: + child->updateVisibility(); + break; + case B3_FALSE: + toRemove.push_back(child); + break; + case B3_UNDEFINED: + child->clearCatalog(); + break; + } + } + + //creating new nodes (if necessary) + for (size_t i = 0; i < myChildrenItems.size(); ++i) { + shared_ptr<NetworkItem> item = myChildrenItems.at(i); + if (!item->isInstanceOf(NetworkCatalogItem::TYPE_ID)) { + continue; + } + if (std::find(itemsWithNodes.begin(), itemsWithNodes.end(), item) != itemsWithNodes.end()) { + continue; + } + NetworkCatalogItem *catalogItem = (NetworkCatalogItem*)(&*item); + if (catalogItem->getVisibility() != B3_FALSE) { + NetworkTreeFactory::createNetworkTree(this, item, i); + } + } + + for (size_t i = 0; i < toRemove.size(); ++i) { + ZLTreeNode* tree = toRemove.at(i); + remove(tree); + } + +} + +void NetworkCatalogTree::clearCatalog() { + myChildrenItems.clear(); + clear(); +} + +const ZLResource &NetworkCatalogTree::resource() const { + return ZLResource::resource("networkView")["libraryItemNode"]; +} diff --git a/fbreader/src/network/tree/NetworkCatalogUtil.cpp b/fbreader/src/network/tree/NetworkCatalogUtil.cpp new file mode 100644 index 0000000..953bf67 --- /dev/null +++ b/fbreader/src/network/tree/NetworkCatalogUtil.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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 <ZLStringUtil.h> +#include <ZLNetworkManager.h> + +#include <ZLBase64EncodedImage.h> +#include <ZLNetworkImage.h> + +#include "NetworkCatalogUtil.h" + +#include "../NetworkLinkCollection.h" + +shared_ptr<const ZLImage> NetworkCatalogUtil::getImageByNetworkUrl(const std::string &url, const std::string &prefix) { + if (!ZLStringUtil::stringStartsWith(url, prefix)) { + return 0; + } + + return new ZLNetworkImage(ZLMimeType::IMAGE_AUTO, url); +} + +shared_ptr<const ZLImage> NetworkCatalogUtil::getImageByDataUrl(const std::string &url) { + if (!ZLStringUtil::stringStartsWith(url, "data:")) { + return 0; + } + + std::size_t index = url.find(','); + if (index == std::string::npos) { + return 0; + } + + ZLBase64EncodedImage *image = new ZLBase64EncodedImage(ZLMimeType::IMAGE_AUTO); + image->addData(url, index + 1, std::string::npos); + return image; +} + +shared_ptr<const ZLImage> NetworkCatalogUtil::getImageByUrl(const std::string &url) { + shared_ptr<const ZLImage> image; + + image = getImageByNetworkUrl(url, "http://"); + if (!image.isNull()) { + return image; + } + + image = getImageByNetworkUrl(url, "https://"); + if (!image.isNull()) { + return image; + } + + return getImageByDataUrl(url); +} + +class NetworkImageDownloadListener : public ZLNetworkRequest::Listener { +public: + NetworkImageDownloadListener(ZLTreeNode *node) : myNode(node) {} + void finished(const std::string &error) { + if (error.empty()) { + myNode->updated(); + } + } +private: + ZLTreeNode *myNode; +}; + +shared_ptr<const ZLImage> NetworkCatalogUtil::getAndDownloadImageByUrl(const std::string &url, const ZLTreeNode *node) { + shared_ptr<const ZLImage> image = getImageByUrl(url); + + if (!image.isNull()) { + shared_ptr<ZLNetworkRequest> downloadRequest = image->synchronizationData(); + if (!downloadRequest.isNull()) { + downloadRequest->setListener(new NetworkImageDownloadListener(const_cast<ZLTreeNode*>(node))); + ZLNetworkManager::Instance().performAsync(downloadRequest); + } + } + return image; +} diff --git a/fbreader/src/network/tree/NetworkCatalogUtil.h b/fbreader/src/network/tree/NetworkCatalogUtil.h new file mode 100644 index 0000000..0196896 --- /dev/null +++ b/fbreader/src/network/tree/NetworkCatalogUtil.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __NETWORKCATALOGUTIL_H__ +#define __NETWORKCATALOGUTIL_H__ + +#include <string> + +#include <shared_ptr.h> + +#include <ZLTreeNode.h> + +class ZLImage; + +class NetworkCatalogUtil { + +public: + static shared_ptr<const ZLImage> getImageByUrl(const std::string &url); + static shared_ptr<const ZLImage> getAndDownloadImageByUrl(const std::string &url, const ZLTreeNode *node); + +private: + static shared_ptr<const ZLImage> getImageByNetworkUrl(const std::string &url, const std::string &prefix); + static shared_ptr<const ZLImage> getImageByDataUrl(const std::string &url); + +private: + NetworkCatalogUtil(); +}; + +#endif /* __NETWORKCATALOGUTIL_H__ */ diff --git a/fbreader/src/network/tree/NetworkLibrary.cpp b/fbreader/src/network/tree/NetworkLibrary.cpp new file mode 100644 index 0000000..118abd0 --- /dev/null +++ b/fbreader/src/network/tree/NetworkLibrary.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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 <ZLDialogManager.h> + +#include "../NetworkLinkCollection.h" + +//#include "NetworkNodesFactory.h" + +#include "../NetworkItems.h" +#include "../NetworkLinkCollection.h" +#include "../NetworkLink.h" +#include "../SearchResult.h" +#include "../authentication/NetworkAuthenticationManager.h" +#include "../../networkActions/NetworkOperationRunnable.h" +#include "NetworkSearcher.h" +#include "NetworkTreeNodes.h" + +#include "NetworkLibrary.h" + +NetworkLibrary *NetworkLibrary::ourInstance = 0; + +NetworkLibrary &NetworkLibrary::Instance() { + if (ourInstance == 0) { + ourInstance = new NetworkLibrary(); + } + return *ourInstance; +} + +NetworkLibrary::NetworkLibrary() { + //TODO maybe it should be created in showDialog method? + myDialog = ZLDialogManager::Instance().createTreeDialog(ZLResource::resource("networkView")); + myRootTree.setDialog(myDialog); + myFakeRootTree.setDialog(myDialog); + myUpdateVisibility = false; + myChildrenAreInvalid = true; +} + +void NetworkLibrary::showDialog() { + synchronize(); + myDialog->run(&myRootTree); + myDialog->setSearcher(new NetworkSearcher); +} + +void NetworkLibrary::refresh() { + myDialog->onRefresh(); +} + +void NetworkLibrary::makeUpToDate() { + //TODO rewrite this method + NetworkLinkCollection::Instance().initialize(); + NetworkLinkCollection &collection = NetworkLinkCollection::Instance(); + for (std::size_t i = 0; i < collection.size(); ++i) { + NetworkLink &link = collection.link(i); + new NetworkCatalogRootTree(&myRootTree, link, i); + } +} + +void NetworkLibrary::updateVisibility() { + for (size_t i = 0; i < myRootTree.children().size(); ++i) { + ZLTreeNode* tree = myRootTree.children().at(i); + if (NetworkCatalogTree* catalogTree = zlobject_cast<NetworkCatalogTree*>(tree)) { + catalogTree->updateVisibility(); + } + } +} + +RootTree &NetworkLibrary::getFakeCatalogTree() { + return myFakeRootTree; +} + +void NetworkLibrary::synchronize() { + if (myChildrenAreInvalid) { + myChildrenAreInvalid = false; + makeUpToDate(); + } + if (myUpdateVisibility) { + myUpdateVisibility = false; + updateVisibility(); + } +} + +void NetworkLibrary::invalidateVisibility() { + myUpdateVisibility = true; +} diff --git a/fbreader/src/network/tree/NetworkLibrary.h b/fbreader/src/network/tree/NetworkLibrary.h new file mode 100644 index 0000000..026cbbd --- /dev/null +++ b/fbreader/src/network/tree/NetworkLibrary.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __NETWORKLIBRARY_H__ +#define __NETWORKLIBRARY_H__ + +#include <ZLTreeDialog.h> + +#include "NetworkTreeNodes.h" + +class NetworkLibrary { + +public: + static NetworkLibrary &Instance(); + +private: + static NetworkLibrary *ourInstance; + +public: + void showDialog(); + void refresh(); + RootTree &getFakeCatalogTree(); + + void synchronize(); + void invalidateVisibility(); + +private: + NetworkLibrary(); + void makeUpToDate(); + + void updateVisibility(); + +private: + shared_ptr<ZLTreeDialog> myDialog; + RootTree myRootTree; + RootTree myFakeRootTree; + bool myUpdateVisibility; + bool myChildrenAreInvalid; +}; + +#endif /* __NETWORKLIBRARY_H__ */ diff --git a/fbreader/src/network/tree/NetworkSearcher.cpp b/fbreader/src/network/tree/NetworkSearcher.cpp new file mode 100644 index 0000000..10d318e --- /dev/null +++ b/fbreader/src/network/tree/NetworkSearcher.cpp @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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 <ZLNetworkManager.h> +#include <ZLDialogManager.h> +#include <ZLTimeManager.h> + +#include "../authentication/NetworkAuthenticationManager.h" +#include "../../networkActions/NetworkOperationRunnable.h" +#include "../NetworkLinkCollection.h" +#include "../NetworkLink.h" +#include "../NetworkOperationData.h" +#include "../NetworkErrors.h" +#include "NetworkTreeNodes.h" +#include "NetworkLibrary.h" +#include "NetworkSearcher.h" + +//TODO rewrite code to not to use fake network link + +NetworkSearcher::NetworkSearcher() { } + +void NetworkSearcher::simpleSearch(const std::string &pattern) { + //TODO maybe move code for simple search from NetworkLinkCollection to here + NetworkCatalogTree *tree = new SearchCatalogTree(&NetworkLibrary::Instance().getFakeCatalogTree(), new AllCatalogsSearchItem(myFakeLink, pattern)); + tree->expand(); +} + +AllCatalogsSearchItem::AllCatalogsSearchItem(const NetworkLink &link, const std::string &pattern) : + NetworkCatalogItem(link, std::string(), std::string(), UrlInfoCollection()), + myPattern(pattern) { +} + +class AllCatalogsSearchItemListener : public ZLNetworkRequest::Listener { +public: + AllCatalogsSearchItemListener(AllCatalogsSearchItem &item, + NetworkItem::List &children, + shared_ptr<ZLNetworkRequest::Listener> listener, + ZLNetworkRequest::Vector requestList, + std::vector<shared_ptr<NetworkOperationData> > dataList) : + myItem(item), + myChildren(children), + myListener(listener), + myDataList(dataList), + myHolder(this) { + myItemFound = false; + myCollection = new NetworkBookCollection; + myCounter = 0; + performRequests(requestList); + } + + void performRequests(ZLNetworkRequest::Vector requestList) { + for (std::size_t i = 0; i < requestList.size(); ++i) { + shared_ptr<ZLNetworkRequest> request = requestList.at(i); + request->setListener(myHolder); + ++myCounter; + ZLNetworkManager::Instance().performAsync(request); + } + } + + void finished(const std::string &error) { + --myCounter; + + ZLNetworkRequest::Vector requestList; + + for (std::size_t i = 0; i < myDataList.size(); ++i) { + shared_ptr<NetworkOperationData> data = myDataList.at(i); + for (std::size_t j = 0; j < data->Items.size(); ++j) { + myCollection->addBook(data->Items.at(j)); + } + + if (!data->Items.empty()) { + shared_ptr<ZLNetworkRequest> request = data->resume(); + if (!request.isNull()) { + request->setListener(myHolder); + requestList.push_back(request); + } + } + } + + + if (!myCollection->books().empty()) { + myItem.onChildrenLoaded(myChildren, myCollection, myListener); + myChildren.clear(); + myCollection->clear(); + } + + if (!requestList.empty()) { + performRequests(requestList); + } + + if (myCounter == 0) { + ZLTimeManager::deleteLater(myHolder); + myHolder.reset(); //destroy itself + } + } + +private: + AllCatalogsSearchItem &myItem; + NetworkItem::List &myChildren; + shared_ptr<ZLNetworkRequest::Listener> myListener; + shared_ptr<NetworkBookCollection> myCollection; //TODO maybe remove this class using + + bool myItemFound; + + std::vector<shared_ptr<NetworkOperationData> > myDataList; + int myCounter; +// std::string myErrorMessage; + shared_ptr<ZLNetworkRequest::Listener> myHolder; //for keeping this instance alive +}; + +std::string AllCatalogsSearchItem::loadChildren(NetworkItem::List &children, shared_ptr<ZLNetworkRequest::Listener> listener) { + ZLNetworkRequest::Vector requestList; + std::vector<shared_ptr<NetworkOperationData> > dataList; + + const NetworkLinkCollection::LinkVector &links = NetworkLinkCollection::Instance().activeLinks(); + for (std::size_t i = 0; i < links.size(); ++i) { + const NetworkLink &link = *links.at(i); + shared_ptr<NetworkOperationData> data = new NetworkOperationData(link); + + shared_ptr<ZLNetworkRequest> request = link.simpleSearchData(*data, myPattern); + if (!request.isNull()) { + dataList.push_back(data); + requestList.push_back(request); + } + } + + new AllCatalogsSearchItemListener(*this, children, listener, requestList, dataList); + + return std::string(); +} + +void AllCatalogsSearchItem::onChildrenLoaded(NetworkItem::List &children, shared_ptr<NetworkBookCollection> collection, shared_ptr<ZLNetworkRequest::Listener> listener) { + if (!collection.isNull()) { + const NetworkItem::List &books = collection->books(); + children.assign(books.begin(), books.end()); + } + listener->finished(); +} + +FakeNetworkLink::FakeNetworkLink() : NetworkLink("") { } + +shared_ptr<ZLNetworkRequest> FakeNetworkLink::simpleSearchData(NetworkOperationData &/*data*/, const std::string &/*pattern*/) const { + return 0; +} + +shared_ptr<ZLNetworkRequest> FakeNetworkLink::advancedSearchData(NetworkOperationData &/*data*/, const std::string &/*titleAndSeries*/, const std::string &/*author*/, const std::string &/*tag*/, const std::string &/*annotation*/) const { + return 0; +} + +shared_ptr<ZLNetworkRequest> FakeNetworkLink::resume(NetworkOperationData &/*data*/) const { + return 0; +} + +shared_ptr<NetworkAuthenticationManager> FakeNetworkLink::authenticationManager() const { + return 0; +} + +shared_ptr<NetworkItem> FakeNetworkLink::libraryItem() const { + return 0; +} + +void FakeNetworkLink::rewriteUrl(std::string &/*url*/, bool /*isUrlExternal*/) const { +} diff --git a/fbreader/src/network/tree/NetworkSearcher.h b/fbreader/src/network/tree/NetworkSearcher.h new file mode 100644 index 0000000..08ebc35 --- /dev/null +++ b/fbreader/src/network/tree/NetworkSearcher.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __NETWORKSEARCHER_H__ +#define __NETWORKSEARCHER_H__ + +#include <ZLTreeSearcher.h> + +#include "../NetworkBookCollection.h" +#include "../NetworkItems.h" + +//TODO rewrite code to not to use fake network link +class FakeNetworkLink : public NetworkLink { +public: + FakeNetworkLink(); + shared_ptr<ZLNetworkRequest> simpleSearchData(NetworkOperationData &data, const std::string &pattern) const; + shared_ptr<ZLNetworkRequest> advancedSearchData(NetworkOperationData &data, const std::string &titleAndSeries, const std::string &author, const std::string &tag, const std::string &annotation) const; + shared_ptr<ZLNetworkRequest> resume(NetworkOperationData &data) const; + shared_ptr<NetworkAuthenticationManager> authenticationManager() const; + shared_ptr<NetworkItem> libraryItem() const; + void rewriteUrl(std::string &url, bool isUrlExternal = false) const; +}; + +class NetworkSearcher : public ZLTreeSearcher { +public: + NetworkSearcher(); + void simpleSearch(const std::string &pattern); +private: + const FakeNetworkLink myFakeLink; +}; + +class AllCatalogsSearchItem : public NetworkCatalogItem { + +public: + AllCatalogsSearchItem(const NetworkLink &link, const std::string &pattern); + std::string loadChildren(List &children, shared_ptr<ZLNetworkRequest::Listener> listener); + void onChildrenLoaded(List &children, shared_ptr<NetworkBookCollection> collection, shared_ptr<ZLNetworkRequest::Listener> listener); + +private: + std::string myPattern; +}; + +#endif /* __NETWORKSEARCHER_H__ */ diff --git a/fbreader/src/network/tree/NetworkSeriesTree.cpp b/fbreader/src/network/tree/NetworkSeriesTree.cpp new file mode 100644 index 0000000..4456ade --- /dev/null +++ b/fbreader/src/network/tree/NetworkSeriesTree.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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 <set> +#include <algorithm> + +#include <ZLResource.h> +#include <ZLImage.h> +#include <ZLStringUtil.h> + +#include "NetworkCatalogUtil.h" +#include "NetworkTreeNodes.h" + +const ZLTypeId NetworkSeriesTree::TYPE_ID(NetworkTree::TYPE_ID); + +const ZLTypeId &NetworkSeriesTree::typeId() const { + return TYPE_ID; +} + +const ZLResource &NetworkSeriesTree::resource() const { + return ZLResource::resource("networkView")["seriesNode"]; +} + +NetworkSeriesTree::NetworkSeriesTree(NetworkTree *parent, const std::string &seriesTitle) : + NetworkTree(parent), mySeriesTitle(seriesTitle) { + init(); +} + +void NetworkSeriesTree::init() { + //registerExpandTreeAction(); +} + +std::string NetworkSeriesTree::title() const { + return mySeriesTitle; +} + +std::string NetworkSeriesTree::subtitle() const { + return ZLStringUtil::printf(resource()["booksCount"].value((int)children().size()), (unsigned int)children().size()); +} + +static const size_t MAX_BATCH_SIZE = 6; + +shared_ptr<const ZLImage> NetworkSeriesTree::image() const { + if (myImages.empty()) { + for (size_t i = 0; i < std::min(children().size(), MAX_BATCH_SIZE); ++i) { + NetworkBookTree *bookTree = zlobject_cast<NetworkBookTree*>(children().at(i)); + if (!bookTree) { + continue; + } + NetworkItem::UrlInfoCollection urlByType = bookTree->book().URLByType; + std::string url = urlByType[NetworkItem::URL_COVER]; + myImages.push_back(NetworkCatalogUtil::getAndDownloadImageByUrl(url, this)); + } + } + return ZLImageManager::Instance().makeBatchImage(myImages, FBTree::defaultCoverImage("booktree-book.png")); +} diff --git a/fbreader/src/network/tree/NetworkTree.cpp b/fbreader/src/network/tree/NetworkTree.cpp new file mode 100644 index 0000000..ac7b39a --- /dev/null +++ b/fbreader/src/network/tree/NetworkTree.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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 "NetworkTreeNodes.h" + +const ZLTypeId NetworkTree::TYPE_ID(FBTree::TYPE_ID); + +const ZLTypeId &NetworkTree::typeId() const { + return TYPE_ID; +} + + +NetworkTree::NetworkTree(RootTree *parent, std::size_t position) : FBTree(parent, position) { } + +NetworkTree::NetworkTree(NetworkTree *parent, std::size_t position) : FBTree(parent, position) { } diff --git a/fbreader/src/network/tree/NetworkTreeFactory.cpp b/fbreader/src/network/tree/NetworkTreeFactory.cpp new file mode 100644 index 0000000..0868034 --- /dev/null +++ b/fbreader/src/network/tree/NetworkTreeFactory.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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 "NetworkTreeFactory.h" + +#include "NetworkTreeNodes.h" + +#include "../NetworkBookCollection.h" + +NetworkTreeFactory::NetworkTreeFactory() { +} + +ZLTreeTitledNode *NetworkTreeFactory::createNetworkTree(NetworkCatalogTree *parent, shared_ptr<NetworkItem> item, std::size_t position) { + if (item->isInstanceOf(NetworkCatalogItem::TYPE_ID)) { + NetworkCatalogItem *catalogItem = (NetworkCatalogItem*)(&*item); + if (catalogItem->getVisibility() == B3_FALSE) { + return 0; + } + NetworkCatalogTree *ptr = new NetworkCatalogTree(parent, item, position); + ptr->item().onDisplayItem(); + return ptr; + } else if (item->isInstanceOf(NetworkBookItem::TYPE_ID)) { + return new NetworkBookTree(parent, item, NetworkBookTree::AUTHORS); + } + return 0; +} + +void NetworkTreeFactory::fillAuthorTree(NetworkTree *parent, const NetworkItem::List &books) { + NetworkSeriesTree *seriesTree = 0; + NetworkAuthorTree *authorTree = 0; + + int flags = NetworkCatalogItem::FLAGS_DEFAULT; + if (NetworkCatalogTree* catalogTree = zlobject_cast<NetworkCatalogTree*>(parent)) { + flags = catalogTree->item().getFlags(); + } + NetworkBookTree::SummaryType booksSummaryType = NetworkBookTree::AUTHORS; + if ((parent->isInstanceOf(NetworkCatalogTree::TYPE_ID) && + (flags & NetworkCatalogItem::FLAG_SHOW_AUTHOR) == 0) || + parent->isInstanceOf(NetworkAuthorTree::TYPE_ID)) { + booksSummaryType = NetworkBookTree::NONE; + } + + for (NetworkItem::List::const_iterator it = books.begin(); it != books.end(); ++it) { + if (!(*it)->isInstanceOf(NetworkBookItem::TYPE_ID)) { + continue; + } + const NetworkBookItem &book = (const NetworkBookItem &) **it; + + //TODO split this method on smaller parts + switch (flags & NetworkCatalogItem::FLAGS_GROUP) { + case NetworkCatalogItem::FLAG_GROUP_BY_SERIES: + if (book.SeriesTitle.empty()) { + new NetworkBookTree(parent, *it, booksSummaryType); + } else { + if (seriesTree == 0 || seriesTree->title() != book.SeriesTitle) { + seriesTree = new NetworkSeriesTree(parent, book.SeriesTitle); + } + new NetworkBookTree(seriesTree, *it, booksSummaryType); + } + break; + case NetworkCatalogItem::FLAG_GROUP_MORE_THAN_1_BOOK_BY_SERIES: + { + std::string seriesTitle = book.SeriesTitle; + if (!seriesTitle.empty() && (seriesTree == 0 || seriesTree->title() != seriesTitle)) { + NetworkItem::List::const_iterator jt = it + 1; + while (jt != books.end() && !(*jt)->isInstanceOf(NetworkBookItem::TYPE_ID)) { + ++jt; + } + if (jt == books.end()) { + seriesTitle.clear(); + } else { + const NetworkBookItem &next = (const NetworkBookItem&)**jt; + if (next.SeriesTitle != seriesTitle) { + seriesTitle.clear(); + } + } + } + if (seriesTitle.empty()) { + seriesTree = 0; + new NetworkBookTree(parent, *it, booksSummaryType); + } else { + if (seriesTree == 0 || seriesTree->title() != seriesTitle) { + seriesTree = new NetworkSeriesTree(parent, seriesTitle); + } + new NetworkBookTree(seriesTree, *it, booksSummaryType); + } + } + break; + case NetworkCatalogItem::FLAG_GROUP_BY_AUTHOR: + if (book.Authors.empty()) { + new NetworkBookTree(parent, *it, booksSummaryType); + } else { + const NetworkBookItem::AuthorData &author = book.Authors.front(); + if (authorTree == 0 || authorTree->author() != author) { + authorTree = new NetworkAuthorTree(parent, author); + } + new NetworkBookTree(authorTree, *it, booksSummaryType); + } + break; + default: + new NetworkBookTree(parent, *it, booksSummaryType); + break; + } + + + } +} diff --git a/fbreader/src/network/tree/NetworkTreeFactory.h b/fbreader/src/network/tree/NetworkTreeFactory.h new file mode 100644 index 0000000..b53213e --- /dev/null +++ b/fbreader/src/network/tree/NetworkTreeFactory.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __NETWORKTREEFACTORY_H__ +#define __NETWORKTREEFACTORY_H__ + +#include "../NetworkItems.h" + +class NetworkBookCollection; +class FBTree; +class NetworkCatalogTree; +class NetworkTree; +class ZLTreeTitledNode; + + +class NetworkTreeFactory { + +private: + NetworkTreeFactory(); + +public: + static ZLTreeTitledNode *createNetworkTree(NetworkCatalogTree *parent, shared_ptr<NetworkItem> item, std::size_t position = (std::size_t)-1); + static void fillAuthorTree(NetworkTree *parent, const NetworkItem::List &books); +}; + +#endif /* __NETWORKTREEFACTORY_H__ */ diff --git a/fbreader/src/network/tree/NetworkTreeNodes.h b/fbreader/src/network/tree/NetworkTreeNodes.h new file mode 100644 index 0000000..fcc76f6 --- /dev/null +++ b/fbreader/src/network/tree/NetworkTreeNodes.h @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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. + */ + +#ifndef __NETWORKTREENODES_H__ +#define __NETWORKTREENODES_H__ + +#include <ZLResource.h> +#include <ZLExecutionUtil.h> + +#include <ZLTreeNode.h> +#include <ZLTreeDialog.h> +#include <ZLTreePageNode.h> + +#include "../NetworkLink.h" +#include "../../tree/FBTree.h" + +//maybe RootTree should be nested class for NetworkLibrary? +class RootTree : public ZLTreeNode { + +public: + static const ZLTypeId TYPE_ID; + +private: + const ZLTypeId &typeId() const; + +public: + RootTree(); + void setDialog(shared_ptr<ZLTreeDialog> dialog); + + +protected: + ZLTreeListener *listener() const; + +private: + shared_ptr<ZLTreeDialog> myListener; +}; + +class NetworkTree : public FBTree { + +public: + static const ZLTypeId TYPE_ID; + +private: + const ZLTypeId &typeId() const; + +public: + NetworkTree(RootTree *parent, std::size_t position); + NetworkTree(NetworkTree *parent, std::size_t position = (std::size_t)-1); +}; + +class NetworkCatalogTree : public NetworkTree { + +public: + static const ZLTypeId TYPE_ID; + +private: + const ZLTypeId &typeId() const; + +public: + NetworkCatalogTree(RootTree *parent, shared_ptr<NetworkItem> item, std::size_t position = (std::size_t)-1); + NetworkCatalogTree(NetworkCatalogTree *parent, shared_ptr<NetworkItem> item, std::size_t position = (std::size_t)-1); + + std::string title() const; + std::string subtitle() const; + shared_ptr<const ZLImage> image() const; + + void requestChildren(shared_ptr<ZLNetworkRequest::Listener> listener); + void requestMoreChildren(shared_ptr<ZLNetworkRequest::Listener> listener); + virtual void onChildrenReceived(NetworkItem::List &childrens, const std::string &error); + + NetworkCatalogItem &item(); + + void updateVisibility(); + void clearCatalog(); + +private: + void init(); + void notifyListeners(const std::string &error); + +private: + void onAuthCheck(const std::string &error); + +private: + const ZLResource &resource() const; + +private: + shared_ptr<NetworkItem> myItem; + NetworkItem::List myChildrenItems; + + std::vector<shared_ptr<ZLNetworkRequest::Listener> > myListeners; + mutable shared_ptr<const ZLImage> myImage; + +friend class NetworkTreeFactory; +friend class NetworkCatalogTreeAuthListener; +}; + +class NetworkCatalogRootTree : public NetworkCatalogTree { + +public: + static const ZLTypeId TYPE_ID; + +private: + const ZLTypeId &typeId() const; + +public: + class LoginAction; + class LogoutAction; + class TopupAccountAction; + class PasswordRecoveryAction; + class RegisterUserAction; + +public: + NetworkCatalogRootTree(RootTree *parent, NetworkLink &link, std::size_t position); + void init(); + +private: + const ZLResource &resource() const; + +private: + NetworkLink &myLink; +}; + +class SearchCatalogTree : public NetworkCatalogTree { + +public: + static const ZLTypeId TYPE_ID; + +private: + const ZLTypeId &typeId() const; + +public: + SearchCatalogTree(RootTree *parent, shared_ptr<NetworkItem> item, std::size_t position = (std::size_t)-1); + + void requestChildren(shared_ptr<ZLNetworkRequest::Listener> listener); + void onChildrenReceived(NetworkItem::List &childrens, const std::string &error); +}; + +class NetworkAuthorTree : public NetworkTree { + +public: + static const ZLTypeId TYPE_ID; + +private: + const ZLTypeId &typeId() const; + +protected: + NetworkAuthorTree(NetworkTree *parent, const NetworkBookItem::AuthorData &author); + +friend class NetworkTreeFactory; + +public: + const NetworkBookItem::AuthorData &author(); + +private: + void init(); + const ZLResource &resource() const; + shared_ptr<const ZLImage> image() const; + std::string title() const; + +private: + NetworkBookItem::AuthorData myAuthor; +}; + +class NetworkSeriesTree : public NetworkTree { + +public: + static const ZLTypeId TYPE_ID; + +private: + const ZLTypeId &typeId() const; + +protected: + NetworkSeriesTree(NetworkTree *parent, const std::string &seriesTitle); + +friend class NetworkTreeFactory; + +private: + void init(); + const ZLResource &resource() const; + shared_ptr<const ZLImage> image() const; + std::string title() const; + std::string subtitle() const; + +private: + std::string mySeriesTitle; + mutable std::vector<shared_ptr<const ZLImage> > myImages; +}; + +class NetworkBookTree : public ZLTreePageNode { + +public: + static const ZLTypeId TYPE_ID; + +private: + const ZLTypeId &typeId() const; + +public: + enum SummaryType { AUTHORS, NONE }; + +private: + NetworkBookTree(NetworkTree *parent, shared_ptr<NetworkItem> book, SummaryType summaryType); + void init(); + +friend class NetworkTreeFactory; + +public: + const NetworkBookItem &book() const; + +public: + const ZLResource &resource() const; + shared_ptr<const ZLImage> image() const; + shared_ptr<const ZLImage> fullImage() const; + std::string title() const; + std::string subtitle() const; + + shared_ptr<ZLTreePageInfo> getPageInfo(); + +private: + class BookItemWrapper : public ZLTreePageInfo { + + public: + BookItemWrapper(NetworkBookTree &tree, shared_ptr<NetworkItem> bookItem); + + bool isPageInfoLoaded(); + void loadAll(shared_ptr<ZLNetworkRequest::Listener> listener); + void onInformationLoaded(ZLUserDataHolder &data, const std::string &error); + void onCoverLoaded(ZLUserDataHolder &data, const std::string &error); + + public: + std::string title() const; + std::vector<std::string> authors() const; + std::vector<std::string> tags() const; + std::string summary() const; + shared_ptr<const ZLImage> image() const; + + //TODO maybe store actions in other place? + const std::vector<shared_ptr<ZLTreeAction> > &actions() const; + std::string actionText(const shared_ptr<ZLTreeAction> &action) const; + const std::vector<shared_ptr<ZLTreeAction> > relatedActions() const; + + private: + NetworkBookItem &book() const; + + private: + NetworkBookTree &myTree; + shared_ptr<NetworkItem> myBookItem; + mutable bool myIsInitialized; + + mutable std::vector<shared_ptr<ZLTreeAction> > myRelatedActions; + }; + +private: + shared_ptr<NetworkItem> myBook; + SummaryType mySummaryType; + mutable shared_ptr<const ZLImage> myImage; + shared_ptr<ZLTreePageInfo> myPageInfo; +}; + +#endif /* __NETWORKTREENODES_H__ */ diff --git a/fbreader/src/network/tree/RootTree.cpp b/fbreader/src/network/tree/RootTree.cpp new file mode 100644 index 0000000..8aad8a5 --- /dev/null +++ b/fbreader/src/network/tree/RootTree.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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 "NetworkTreeNodes.h" + +const ZLTypeId RootTree::TYPE_ID(ZLTreeNode::TYPE_ID); + +const ZLTypeId &RootTree::typeId() const { + return TYPE_ID; +} + + +RootTree::RootTree() { + +} + +void RootTree::setDialog(shared_ptr<ZLTreeDialog> dialog) { + myListener = dialog; +} + +ZLTreeListener *RootTree::listener() const { + if (myListener.isNull()) { + return 0; + } + return &(*myListener); +} diff --git a/fbreader/src/network/tree/SearchCatalogTree.cpp b/fbreader/src/network/tree/SearchCatalogTree.cpp new file mode 100644 index 0000000..62ee967 --- /dev/null +++ b/fbreader/src/network/tree/SearchCatalogTree.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <[email protected]> + * + * 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 "NetworkTreeNodes.h" + +const ZLTypeId SearchCatalogTree::TYPE_ID(NetworkCatalogTree::TYPE_ID); + +const ZLTypeId &SearchCatalogTree::typeId() const { + return TYPE_ID; +} + +SearchCatalogTree::SearchCatalogTree(RootTree *parent, shared_ptr<NetworkItem> item, std::size_t position) : + NetworkCatalogTree(parent, item, position) { + //TODO maybe remove this class +} + +void SearchCatalogTree::requestChildren(shared_ptr<ZLNetworkRequest::Listener> listener) { + notifySearchStarted(); + NetworkCatalogTree::requestChildren(listener); +} + +void SearchCatalogTree::onChildrenReceived(NetworkItem::List &childrens, const std::string &error) { + notifySearchStopped(); + NetworkCatalogTree::onChildrenReceived(childrens, error); +} |