diff --git a/export/akregatorstorageexporter.cpp b/export/akregatorstorageexporter.cpp index 05fba480..9e5e63ed 100644 --- a/export/akregatorstorageexporter.cpp +++ b/export/akregatorstorageexporter.cpp @@ -1,392 +1,392 @@ /* * This file is part of akregatorstorageexporter * * Copyright (C) 2009 Frank Osterfeld * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #include "feedstorage.h" #include "storage.h" #include "storagefactory.h" #include "storagefactoryregistry.h" #include "plugin.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Akregator; using namespace Akregator::Backend; namespace { static QString akregatorNamespace() { return QStringLiteral("http://akregator.kde.org/StorageExporter#"); } enum TextMode { PlainText, Html }; enum Status { Deleted = 0x01, Trash = 0x02, New = 0x04, Read = 0x08, Keep = 0x10 }; class Element { public: Element(const QString &ns_, const QString &name_) : ns(ns_) , name(name_) , qualifiedName(ns + QLatin1Char(':') + name) { } const QString ns; const QString name; const QString qualifiedName; void writeStartElement(QXmlStreamWriter &writer) const { if (!ns.isNull()) { writer.writeStartElement(ns, name); } else { writer.writeStartElement(name); } } void write(const QVariant &value, QXmlStreamWriter &writer, TextMode mode = PlainText) const { const QVariant qv(value); Q_ASSERT(qv.canConvert(QVariant::String)); const QString str = qv.toString(); if (str.isEmpty()) { return; } if (ns.isEmpty()) { writer.writeStartElement(name); } else { writer.writeStartElement(ns, name); } if (mode == Html) { writer.writeAttribute(QStringLiteral("type"), QStringLiteral("html")); } writer.writeCharacters(str); writer.writeEndElement(); } }; struct Elements { Elements() : atomNS(Syndication::Atom::atom1Namespace()) , akregatorNS(akregatorNamespace()) , commentNS(Syndication::commentApiNamespace()) , title(atomNS, QStringLiteral("title")) , summary(atomNS, QStringLiteral("summary")) , content(atomNS, QStringLiteral("content")) , link(atomNS, QStringLiteral("link")) , language(atomNS, QStringLiteral("language")) , feed(atomNS, QStringLiteral("feed")) , guid(atomNS, QStringLiteral("id")) , published(atomNS, QStringLiteral("published")) , updated(atomNS, QStringLiteral("updated")) , commentsCount(Syndication::slashNamespace(), QStringLiteral("comments")) , commentsFeed(commentNS, QStringLiteral("commentRss")) , commentPostUri(commentNS, QStringLiteral("comment")) , commentsLink(akregatorNS, QStringLiteral("commentsLink")) , hash(akregatorNS, QStringLiteral("hash")) , guidIsHash(akregatorNS, QStringLiteral("idIsHash")) , name(atomNS, QStringLiteral("name")) , uri(atomNS, QStringLiteral("uri")) , email(atomNS, QStringLiteral("email")) , author(atomNS, QStringLiteral("author")) , category(atomNS, QStringLiteral("category")) , entry(atomNS, QStringLiteral("entry")) , itemProperties(akregatorNS, QStringLiteral("itemProperties")) , readStatus(akregatorNS, QStringLiteral("readStatus")) , deleted(akregatorNS, QStringLiteral("deleted")) , important(akregatorNS, QStringLiteral("important")) { } const QString atomNS; const QString akregatorNS; const QString commentNS; const Element title; const Element summary; const Element content; const Element link; const Element language; const Element feed; const Element guid; const Element published; const Element updated; const Element commentsCount; const Element commentsFeed; const Element commentPostUri; const Element commentsLink; const Element hash; const Element guidIsHash; const Element name; const Element uri; const Element email; const Element author; const Element category; const Element entry; const Element itemProperties; const Element readStatus; const Element deleted; const Element important; static const Elements instance; }; const Elements Elements::instance; void writeAttributeIfNotEmpty(const QString &element, const QVariant &value, QXmlStreamWriter &writer) { const QString text = value.toString(); if (text.isEmpty()) { return; } writer.writeAttribute(element, text); } void writeEnclosure(const QString &url, const QString &type, int length, QXmlStreamWriter &writer) { Elements::instance.link.writeStartElement(writer); writer.writeAttribute(QStringLiteral("rel"), QStringLiteral("enclosure")); writeAttributeIfNotEmpty(QStringLiteral("href"), url, writer); writeAttributeIfNotEmpty(QStringLiteral("type"), type, writer); if (length > 0) { writer.writeAttribute(QStringLiteral("length"), QString::number(length)); } writer.writeEndElement(); } void writeLink(const QString &url, QXmlStreamWriter &writer) { if (url.isEmpty()) { return; } Elements::instance.link.writeStartElement(writer); writer.writeAttribute(QStringLiteral("rel"), QStringLiteral("alternate")); writeAttributeIfNotEmpty(QStringLiteral("href"), url, writer); writer.writeEndElement(); } void writeAuthor(const QString &name, const QString &uri, const QString &email, QXmlStreamWriter &writer) { if (name.isEmpty() && uri.isEmpty() && email.isEmpty()) { return; } const QString atomNS = Syndication::Atom::atom1Namespace(); Elements::instance.author.writeStartElement(writer); Elements::instance.name.write(name, writer); Elements::instance.uri.write(uri, writer); Elements::instance.email.write(email, writer); writer.writeEndElement(); // } static void writeItem(FeedStorage *storage, const QString &guid, QXmlStreamWriter &writer) { Elements::instance.entry.writeStartElement(writer); Elements::instance.guid.write(guid, writer); - const uint published = storage->pubDate(guid); - if (published > 0) { - const QString pdStr = QDateTime::fromTime_t(published).toString(Qt::ISODate); + const QDateTime published = storage->pubDate(guid); + if (published.isValid()) { + const QString pdStr = published.toString(Qt::ISODate); Elements::instance.published.write(pdStr, writer); } const int status = storage->status(guid); Elements::instance.itemProperties.writeStartElement(writer); if (status & Deleted) { Elements::instance.deleted.write(QStringLiteral("true"), writer); writer.writeEndElement(); // writer.writeEndElement(); // return; } Elements::instance.hash.write(QString::number(storage->hash(guid)), writer); if (storage->guidIsHash(guid)) { Elements::instance.guidIsHash.write(QStringLiteral("true"), writer); } if (status & New) { Elements::instance.readStatus.write(QStringLiteral("new"), writer); } else if ((status & Read) == 0) { Elements::instance.readStatus.write(QStringLiteral("unread"), writer); } if (status & Keep) { Elements::instance.important.write(QStringLiteral("true"), writer); } writer.writeEndElement(); // Elements::instance.title.write(storage->title(guid), writer, Html); writeLink(storage->guidIsPermaLink(guid) ? guid : storage->link(guid), writer); Elements::instance.summary.write(storage->description(guid), writer, Html); Elements::instance.content.write(storage->content(guid), writer, Html); writeAuthor(storage->authorName(guid), storage->authorUri(guid), storage->authorEMail(guid), writer); if (const int commentsCount = storage->comments(guid)) { Elements::instance.commentsCount.write(QString::number(commentsCount), writer); } Elements::instance.commentsLink.write(storage->commentsLink(guid), writer); bool hasEnc = false; QString encUrl, encType; int encLength = 0; storage->enclosure(guid, hasEnc, encUrl, encType, encLength); if (hasEnc) { writeEnclosure(encUrl, encType, encLength, writer); } writer.writeEndElement(); // } static void serialize(FeedStorage *storage, const QString &url, QIODevice *device) { Q_ASSERT(storage); Q_ASSERT(device); QXmlStreamWriter writer(device); writer.setAutoFormatting(true); writer.setAutoFormattingIndent(2); writer.writeStartDocument(); Elements::instance.feed.writeStartElement(writer); writer.writeDefaultNamespace(Syndication::Atom::atom1Namespace()); writer.writeNamespace(Syndication::commentApiNamespace(), QStringLiteral("comment")); writer.writeNamespace(akregatorNamespace(), QStringLiteral("akregator")); writer.writeNamespace(Syndication::itunesNamespace(), QStringLiteral("itunes")); Elements::instance.title.write(i18n("Akregator Export for %1", url), writer, Html); Q_FOREACH (const QString &i, storage->articles()) { writeItem(storage, i, writer); } writer.writeEndElement(); // writer.writeEndDocument(); } static void serialize(Storage *storage, const QString &url, QIODevice *device) { serialize(storage->archiveFor(url), url, device); } static KService::List queryStoragePlugins() { return KServiceTypeTrader::self()->query(QStringLiteral("Akregator/Plugin"), QStringLiteral("[X-KDE-akregator-framework-version] == %1 and [X-KDE-akregator-plugintype] == 'storage' and [X-KDE-akregator-rank] > 0").arg(QString:: number( AKREGATOR_PLUGIN_INTERFACE_VERSION))); } static Plugin *createFromService(const KService::Ptr &service) { KPluginLoader loader(*service); KPluginFactory *factory = loader.factory(); if (!factory) { qCritical() << QStringLiteral(" Could not create plugin factory for: %1\n" " Error message: %2").arg(service->library(), loader.errorString()); return nullptr; } return factory->create(); } static void printUsage() { std::cout << "akregatorstorageexporter [--base64] url" << std::endl; } } int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); const QString backend = QStringLiteral("metakit"); if (argc < 2) { printUsage(); return 1; } const bool base64 = qstrcmp(argv[1], "--base64") == 0; if (base64 && argc < 3) { printUsage(); return 1; } const int pos = base64 ? 2 : 1; const QString url = QUrl::fromEncoded(base64 ? QByteArray::fromBase64(argv[pos]) : QByteArray(argv[pos])).toString(); Q_FOREACH (const KService::Ptr &i, queryStoragePlugins()) { if (Plugin *const plugin = createFromService(i)) { plugin->initialize(); } } const StorageFactory *const storageFactory = StorageFactoryRegistry::self()->getFactory(backend); if (!storageFactory) { qCritical("Could not create storage factory for %s.", qPrintable(backend)); return 1; } Storage *const storage = storageFactory->createStorage(QStringList()); if (!storage) { qCritical("Could not create storage object for %s.", qPrintable(backend)); return 1; } QFile out; if (!out.open(stdout, QIODevice::WriteOnly)) { qCritical("Could not open stdout for writing: %s", qPrintable(out.errorString())); return 1; } serialize(storage, url, &out); return app.exec(); } diff --git a/interfaces/feedstorage.h b/interfaces/feedstorage.h index 23b95f93..83059ec6 100644 --- a/interfaces/feedstorage.h +++ b/interfaces/feedstorage.h @@ -1,108 +1,109 @@ /* This file is part of Akregator. Copyright (C) 2005 Frank Osterfeld 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. As a special exception, permission is given to link this program with any edition of Qt, and distribute the resulting executable, without including the source code for Qt in the source distribution. */ #ifndef AKREGATOR_BACKEND_FEEDSTORAGE_H #define AKREGATOR_BACKEND_FEEDSTORAGE_H #include #include class QString; class QStringList; +class QDateTime; namespace Akregator { namespace Backend { class Storage; class FeedStorage : public QObject //krazy:exclude=qobject { public: virtual int unread() const = 0; virtual void setUnread(int unread) = 0; virtual int totalCount() const = 0; virtual int lastFetch() const = 0; virtual void setLastFetch(int lastFetch) = 0; /** returns the guids of all articles in this storage. */ virtual QStringList articles() const = 0; /** Appends all articles from another storage. If there is already an article in this feed with the same guid, it is replaced by the article from the source @param source the archive which articles should be appended */ virtual void add(FeedStorage *source) = 0; /** reads an article from another storage and adds it to this storage */ virtual void copyArticle(const QString &guid, FeedStorage *source) = 0; /** deletes all articles from the archive */ virtual void clear() = 0; virtual bool contains(const QString &guid) const = 0; virtual void addEntry(const QString &guid) = 0; virtual void deleteArticle(const QString &guid) = 0; virtual int comments(const QString &guid) const = 0; virtual QString commentsLink(const QString &guid) const = 0; virtual void setCommentsLink(const QString &guid, const QString &commentsLink) = 0; virtual void setComments(const QString &guid, int comments) = 0; virtual bool guidIsHash(const QString &guid) const = 0; virtual void setGuidIsHash(const QString &guid, bool isHash) = 0; virtual bool guidIsPermaLink(const QString &guid) const = 0; virtual void setGuidIsPermaLink(const QString &guid, bool isPermaLink) = 0; virtual uint hash(const QString &guid) const = 0; virtual void setHash(const QString &guid, uint hash) = 0; virtual void setDeleted(const QString &guid) = 0; virtual QString link(const QString &guid) const = 0; virtual void setLink(const QString &guid, const QString &link) = 0; - virtual uint pubDate(const QString &guid) const = 0; - virtual void setPubDate(const QString &guid, uint pubdate) = 0; + virtual QDateTime pubDate(const QString &guid) const = 0; + virtual void setPubDate(const QString &guid, const QDateTime &pubdate) = 0; virtual int status(const QString &guid) const = 0; virtual void setStatus(const QString &guid, int status) = 0; virtual QString title(const QString &guid) const = 0; virtual void setTitle(const QString &guid, const QString &title) = 0; virtual QString description(const QString &guid) const = 0; virtual void setDescription(const QString &guid, const QString &description) = 0; virtual QString content(const QString &guid) const = 0; virtual void setContent(const QString &guid, const QString &content) = 0; virtual void setEnclosure(const QString &guid, const QString &url, const QString &type, int length) = 0; virtual void removeEnclosure(const QString &guid) = 0; virtual void setAuthorName(const QString & /*guid*/, const QString &name) = 0; virtual void setAuthorUri(const QString & /*guid*/, const QString &uri) = 0; virtual void setAuthorEMail(const QString & /*guid*/, const QString &email) = 0; virtual QString authorName(const QString &guid) const = 0; virtual QString authorUri(const QString &guid) const = 0; virtual QString authorEMail(const QString &guid) const = 0; virtual void enclosure(const QString &guid, bool &hasEnclosure, QString &url, QString &type, int &length) const = 0; virtual void close() = 0; virtual void commit() = 0; virtual void rollback() = 0; }; } // namespace Backend } // namespace Akregator #endif // AKREGATOR_BACKEND_FEEDSTORAGE_H diff --git a/plugins/mk4storage/feedstoragemk4impl.cpp b/plugins/mk4storage/feedstoragemk4impl.cpp index 0131ef43..c65ae8dd 100644 --- a/plugins/mk4storage/feedstoragemk4impl.cpp +++ b/plugins/mk4storage/feedstoragemk4impl.cpp @@ -1,613 +1,614 @@ /* This file is part of Akregator. Copyright (C) 2005 Frank Osterfeld 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. As a special exception, permission is given to link this program with any edition of Qt, and distribute the resulting executable, without including the source code for Qt in the source distribution. */ #include "feedstoragemk4impl.h" #include "storagemk4impl.h" #include #include #include #include #include +#include #include #include #include #include namespace { static uint calcHash(const QString &str) { if (str.isNull()) { // handle null string as "", prevents crash return calcHash(QLatin1String("")); } const char *s = str.toLatin1(); uint hash = 5381; int c; while ((c = *s++)) { hash = ((hash << 5) + hash) + c; // hash*33 + c } return hash; } } namespace Akregator { namespace Backend { class FeedStorageMK4Impl::FeedStorageMK4ImplPrivate { public: FeedStorageMK4ImplPrivate() : modified(false) , pguid("guid") , ptitle("title") , pdescription("description") , pcontent("content") , plink("link") , pcommentsLink("commentsLink") , ptag("tag") , pEnclosureType("enclosureType") , pEnclosureUrl("enclosureUrl") , pcatTerm("catTerm") , pcatScheme("catScheme") , pcatName("catName") , pauthorName("authorName") , pauthorUri("authorUri") , pauthorEMail("authorEMail") , phash("hash") , pguidIsHash("guidIsHash") , pguidIsPermaLink("guidIsPermaLink") , pcomments("comments") , pstatus("status") , ppubDate("pubDate") , pHasEnclosure("hasEnclosure") , pEnclosureLength("enclosureLength") { } QString url; c4_Storage *storage; StorageMK4Impl *mainStorage; c4_View archiveView; bool autoCommit; bool modified; c4_StringProp pguid, ptitle, pdescription, pcontent, plink, pcommentsLink, ptag, pEnclosureType, pEnclosureUrl, pcatTerm, pcatScheme, pcatName, pauthorName, pauthorUri, pauthorEMail; c4_IntProp phash, pguidIsHash, pguidIsPermaLink, pcomments, pstatus, ppubDate, pHasEnclosure, pEnclosureLength; }; FeedStorageMK4Impl::FeedStorageMK4Impl(const QString &url, StorageMK4Impl *main) { d = new FeedStorageMK4ImplPrivate; d->autoCommit = main->autoCommit(); d->url = url; d->mainStorage = main; QString url2 = url; if (url.length() > 255) { url2 = url.left(200) + QString::number(::calcHash(url), 16); } qDebug() << url2; QString t = url2; QString t2 = url2; QString filePath = main->archivePath() + QLatin1Char('/') + t.replace(QLatin1Char('/'), QLatin1Char('_')).replace(QLatin1Char(':'), QLatin1Char('_')); d->storage = new c4_Storage(QString(filePath + QLatin1String(".mk4")).toLocal8Bit(), true); d->archiveView = d->storage->GetAs( "articles[guid:S,title:S,hash:I,guidIsHash:I,guidIsPermaLink:I,description:S,link:S,comments:I,commentsLink:S,status:I,pubDate:I,tags[tag:S],hasEnclosure:I,enclosureUrl:S,enclosureType:S,enclosureLength:I,categories[catTerm:S,catScheme:S,catName:S],authorName:S,content:S,authorUri:S,authorEMail:S]"); c4_View hash = d->storage->GetAs("archiveHash[_H:I,_R:I]"); d->archiveView = d->archiveView.Hash(hash, 1); // hash on guid } FeedStorageMK4Impl::~FeedStorageMK4Impl() { delete d->storage; delete d; d = 0; } void FeedStorageMK4Impl::markDirty() { if (!d->modified) { d->modified = true; // Tell this to mainStorage d->mainStorage->markDirty(); } } void FeedStorageMK4Impl::commit() { if (d->modified) { d->storage->Commit(); } d->modified = false; } void FeedStorageMK4Impl::rollback() { d->storage->Rollback(); } void FeedStorageMK4Impl::close() { if (d->autoCommit) { commit(); } } int FeedStorageMK4Impl::unread() const { return d->mainStorage->unreadFor(d->url); } void FeedStorageMK4Impl::setUnread(int unread) { d->mainStorage->setUnreadFor(d->url, unread); } int FeedStorageMK4Impl::totalCount() const { return d->mainStorage->totalCountFor(d->url); } void FeedStorageMK4Impl::setTotalCount(int total) { d->mainStorage->setTotalCountFor(d->url, total); } int FeedStorageMK4Impl::lastFetch() const { return d->mainStorage->lastFetchFor(d->url); } void FeedStorageMK4Impl::setLastFetch(int lastFetch) { d->mainStorage->setLastFetchFor(d->url, lastFetch); } QStringList FeedStorageMK4Impl::articles() const { QStringList list; int size = d->archiveView.GetSize(); list.reserve(size); for (int i = 0; i < size; ++i) { // fill with guids list += QString::fromLatin1(d->pguid(d->archiveView.GetAt(i))); } return list; } void FeedStorageMK4Impl::addEntry(const QString &guid) { c4_Row row; d->pguid(row) = guid.toLatin1(); if (!contains(guid)) { d->archiveView.Add(row); markDirty(); setTotalCount(totalCount() + 1); } } bool FeedStorageMK4Impl::contains(const QString &guid) const { return findArticle(guid) != -1; } int FeedStorageMK4Impl::findArticle(const QString &guid) const { c4_Row findrow; d->pguid(findrow) = guid.toLatin1(); return d->archiveView.Find(findrow); } void FeedStorageMK4Impl::deleteArticle(const QString &guid) { int findidx = findArticle(guid); if (findidx != -1) { setTotalCount(totalCount() - 1); d->archiveView.RemoveAt(findidx); markDirty(); } } int FeedStorageMK4Impl::comments(const QString &guid) const { int findidx = findArticle(guid); return findidx != -1 ? d->pcomments(d->archiveView.GetAt(findidx)) : 0; } QString FeedStorageMK4Impl::commentsLink(const QString &guid) const { int findidx = findArticle(guid); return findidx != -1 ? QString::fromLatin1(d->pcommentsLink(d->archiveView.GetAt(findidx))) : QLatin1String(""); } bool FeedStorageMK4Impl::guidIsHash(const QString &guid) const { int findidx = findArticle(guid); return findidx != -1 ? d->pguidIsHash(d->archiveView.GetAt(findidx)) : false; } bool FeedStorageMK4Impl::guidIsPermaLink(const QString &guid) const { int findidx = findArticle(guid); return findidx != -1 ? d->pguidIsPermaLink(d->archiveView.GetAt(findidx)) : false; } uint FeedStorageMK4Impl::hash(const QString &guid) const { int findidx = findArticle(guid); return findidx != -1 ? d->phash(d->archiveView.GetAt(findidx)) : 0; } void FeedStorageMK4Impl::setDeleted(const QString &guid) { int findidx = findArticle(guid); if (findidx == -1) { return; } c4_Row row; row = d->archiveView.GetAt(findidx); d->pdescription(row) = ""; d->pcontent(row) = ""; d->ptitle(row) = ""; d->plink(row) = ""; d->pauthorName(row) = ""; d->pauthorUri(row) = ""; d->pauthorEMail(row) = ""; d->pcommentsLink(row) = ""; d->archiveView.SetAt(findidx, row); markDirty(); } QString FeedStorageMK4Impl::link(const QString &guid) const { int findidx = findArticle(guid); return findidx != -1 ? QString::fromLatin1(d->plink(d->archiveView.GetAt(findidx))) : QLatin1String(""); } -uint FeedStorageMK4Impl::pubDate(const QString &guid) const +QDateTime FeedStorageMK4Impl::pubDate(const QString &guid) const { int findidx = findArticle(guid); - return findidx != -1 ? d->ppubDate(d->archiveView.GetAt(findidx)) : 0; + return findidx != -1 ? QDateTime::fromTime_t(d->ppubDate(d->archiveView.GetAt(findidx))) : QDateTime(); } int FeedStorageMK4Impl::status(const QString &guid) const { int findidx = findArticle(guid); return findidx != -1 ? d->pstatus(d->archiveView.GetAt(findidx)) : 0; } void FeedStorageMK4Impl::setStatus(const QString &guid, int status) { int findidx = findArticle(guid); if (findidx == -1) { return; } c4_Row row; row = d->archiveView.GetAt(findidx); d->pstatus(row) = status; d->archiveView.SetAt(findidx, row); markDirty(); } QString FeedStorageMK4Impl::title(const QString &guid) const { int findidx = findArticle(guid); return findidx != -1 ? QString::fromUtf8(d->ptitle(d->archiveView.GetAt(findidx))) : QLatin1String(""); } QString FeedStorageMK4Impl::description(const QString &guid) const { int findidx = findArticle(guid); return findidx != -1 ? QString::fromUtf8(d->pdescription(d->archiveView.GetAt(findidx))) : QLatin1String(""); } QString FeedStorageMK4Impl::content(const QString &guid) const { int findidx = findArticle(guid); return findidx != -1 ? QString::fromUtf8(d->pcontent(d->archiveView.GetAt(findidx))) : QLatin1String(""); } -void FeedStorageMK4Impl::setPubDate(const QString &guid, uint pubdate) +void FeedStorageMK4Impl::setPubDate(const QString &guid, const QDateTime &pubdate) { int findidx = findArticle(guid); if (findidx == -1) { return; } c4_Row row; row = d->archiveView.GetAt(findidx); - d->ppubDate(row) = pubdate; + d->ppubDate(row) = pubdate.toTime_t(); d->archiveView.SetAt(findidx, row); markDirty(); } void FeedStorageMK4Impl::setGuidIsHash(const QString &guid, bool isHash) { int findidx = findArticle(guid); if (findidx == -1) { return; } c4_Row row; row = d->archiveView.GetAt(findidx); d->pguidIsHash(row) = isHash; d->archiveView.SetAt(findidx, row); markDirty(); } void FeedStorageMK4Impl::setLink(const QString &guid, const QString &link) { int findidx = findArticle(guid); if (findidx == -1) { return; } c4_Row row; row = d->archiveView.GetAt(findidx); d->plink(row) = !link.isEmpty() ? link.toLatin1() : ""; d->archiveView.SetAt(findidx, row); markDirty(); } void FeedStorageMK4Impl::setHash(const QString &guid, uint hash) { int findidx = findArticle(guid); if (findidx == -1) { return; } c4_Row row; row = d->archiveView.GetAt(findidx); d->phash(row) = hash; d->archiveView.SetAt(findidx, row); markDirty(); } void FeedStorageMK4Impl::setTitle(const QString &guid, const QString &title) { int findidx = findArticle(guid); if (findidx == -1) { return; } c4_Row row; row = d->archiveView.GetAt(findidx); d->ptitle(row) = !title.isEmpty() ? title.toUtf8().data() : ""; d->archiveView.SetAt(findidx, row); markDirty(); } void FeedStorageMK4Impl::setDescription(const QString &guid, const QString &description) { int findidx = findArticle(guid); if (findidx == -1) { return; } c4_Row row; row = d->archiveView.GetAt(findidx); d->pdescription(row) = !description.isEmpty() ? description.toUtf8().data() : ""; d->archiveView.SetAt(findidx, row); markDirty(); } void FeedStorageMK4Impl::setContent(const QString &guid, const QString &content) { int findidx = findArticle(guid); if (findidx == -1) { return; } c4_Row row; row = d->archiveView.GetAt(findidx); d->pcontent(row) = !content.isEmpty() ? content.toUtf8().data() : ""; d->archiveView.SetAt(findidx, row); markDirty(); } void FeedStorageMK4Impl::setAuthorName(const QString &guid, const QString &author) { int findidx = findArticle(guid); if (findidx == -1) { return; } c4_Row row; row = d->archiveView.GetAt(findidx); d->pauthorName(row) = !author.isEmpty() ? author.toUtf8().data() : ""; d->archiveView.SetAt(findidx, row); markDirty(); } void FeedStorageMK4Impl::setAuthorUri(const QString &guid, const QString &author) { int findidx = findArticle(guid); if (findidx == -1) { return; } c4_Row row; row = d->archiveView.GetAt(findidx); d->pauthorUri(row) = !author.isEmpty() ? author.toUtf8().data() : ""; d->archiveView.SetAt(findidx, row); markDirty(); } void FeedStorageMK4Impl::setAuthorEMail(const QString &guid, const QString &author) { int findidx = findArticle(guid); if (findidx == -1) { return; } c4_Row row; row = d->archiveView.GetAt(findidx); d->pauthorEMail(row) = !author.isEmpty() ? author.toUtf8().data() : ""; d->archiveView.SetAt(findidx, row); markDirty(); } QString FeedStorageMK4Impl::authorName(const QString &guid) const { int findidx = findArticle(guid); return findidx != -1 ? QString::fromUtf8(d->pauthorName(d->archiveView.GetAt(findidx))) : QString(); } QString FeedStorageMK4Impl::authorUri(const QString &guid) const { int findidx = findArticle(guid); return findidx != -1 ? QString::fromUtf8(d->pauthorUri(d->archiveView.GetAt(findidx))) : QString(); } QString FeedStorageMK4Impl::authorEMail(const QString &guid) const { int findidx = findArticle(guid); return findidx != -1 ? QString::fromUtf8(d->pauthorEMail(d->archiveView.GetAt(findidx))) : QString(); } void FeedStorageMK4Impl::setCommentsLink(const QString &guid, const QString &commentsLink) { int findidx = findArticle(guid); if (findidx == -1) { return; } c4_Row row; row = d->archiveView.GetAt(findidx); d->pcommentsLink(row) = !commentsLink.isEmpty() ? commentsLink.toUtf8().data() : ""; d->archiveView.SetAt(findidx, row); markDirty(); } void FeedStorageMK4Impl::setComments(const QString &guid, int comments) { int findidx = findArticle(guid); if (findidx == -1) { return; } c4_Row row; row = d->archiveView.GetAt(findidx); d->pcomments(row) = comments; d->archiveView.SetAt(findidx, row); markDirty(); } void FeedStorageMK4Impl::setGuidIsPermaLink(const QString &guid, bool isPermaLink) { int findidx = findArticle(guid); if (findidx == -1) { return; } c4_Row row; row = d->archiveView.GetAt(findidx); d->pguidIsPermaLink(row) = isPermaLink; d->archiveView.SetAt(findidx, row); markDirty(); } void FeedStorageMK4Impl::add(FeedStorage *source) { QStringList articles = source->articles(); for (QStringList::ConstIterator it = articles.constBegin(); it != articles.constEnd(); ++it) { copyArticle(*it, source); } setUnread(source->unread()); setLastFetch(source->lastFetch()); setTotalCount(source->totalCount()); } void FeedStorageMK4Impl::copyArticle(const QString &guid, FeedStorage *source) { if (!contains(guid)) { addEntry(guid); } setComments(guid, source->comments(guid)); setCommentsLink(guid, source->commentsLink(guid)); setDescription(guid, source->description(guid)); setGuidIsHash(guid, source->guidIsHash(guid)); setGuidIsPermaLink(guid, source->guidIsPermaLink(guid)); setHash(guid, source->hash(guid)); setLink(guid, source->link(guid)); setPubDate(guid, source->pubDate(guid)); setStatus(guid, source->status(guid)); setTitle(guid, source->title(guid)); setAuthorName(guid, source->authorName(guid)); setAuthorUri(guid, source->authorUri(guid)); setAuthorEMail(guid, source->authorEMail(guid)); } void FeedStorageMK4Impl::setEnclosure(const QString &guid, const QString &url, const QString &type, int length) { int findidx = findArticle(guid); if (findidx == -1) { return; } c4_Row row; row = d->archiveView.GetAt(findidx); d->pHasEnclosure(row) = true; d->pEnclosureUrl(row) = !url.isEmpty() ? url.toUtf8().data() : ""; d->pEnclosureType(row) = !type.isEmpty() ? type.toUtf8().data() : ""; d->pEnclosureLength(row) = length; d->archiveView.SetAt(findidx, row); markDirty(); } void FeedStorageMK4Impl::removeEnclosure(const QString &guid) { int findidx = findArticle(guid); if (findidx == -1) { return; } c4_Row row; row = d->archiveView.GetAt(findidx); d->pHasEnclosure(row) = false; d->pEnclosureUrl(row) = ""; d->pEnclosureType(row) = ""; d->pEnclosureLength(row) = -1; d->archiveView.SetAt(findidx, row); markDirty(); } void FeedStorageMK4Impl::enclosure(const QString &guid, bool &hasEnclosure, QString &url, QString &type, int &length) const { int findidx = findArticle(guid); if (findidx == -1) { hasEnclosure = false; url.clear(); type.clear(); length = -1; return; } c4_Row row = d->archiveView.GetAt(findidx); hasEnclosure = d->pHasEnclosure(row); url = QLatin1String(d->pEnclosureUrl(row)); type = QLatin1String(d->pEnclosureType(row)); length = d->pEnclosureLength(row); } void FeedStorageMK4Impl::clear() { d->storage->RemoveAll(); setUnread(0); markDirty(); } } // namespace Backend } // namespace Akregator diff --git a/plugins/mk4storage/feedstoragemk4impl.h b/plugins/mk4storage/feedstoragemk4impl.h index b0dc810c..1e1c6831 100644 --- a/plugins/mk4storage/feedstoragemk4impl.h +++ b/plugins/mk4storage/feedstoragemk4impl.h @@ -1,102 +1,102 @@ /* This file is part of Akregator. Copyright (C) 2005 Frank Osterfeld 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. As a special exception, permission is given to link this program with any edition of Qt, and distribute the resulting executable, without including the source code for Qt in the source distribution. */ #ifndef AKREGATOR_BACKEND_FEEDSTORAGEMK4IMPL_H #define AKREGATOR_BACKEND_FEEDSTORAGEMK4IMPL_H #include "feedstorage.h" namespace Akregator { namespace Backend { class StorageMK4Impl; class FeedStorageMK4Impl : public FeedStorage { public: FeedStorageMK4Impl(const QString &url, StorageMK4Impl *main); ~FeedStorageMK4Impl(); void add(FeedStorage *source) override; void copyArticle(const QString &guid, FeedStorage *source) override; void clear() override; int unread() const override; void setUnread(int unread) override; int totalCount() const override; int lastFetch() const override; void setLastFetch(int lastFetch) override; QStringList articles() const override; bool contains(const QString &guid) const override; void addEntry(const QString &guid) override; void deleteArticle(const QString &guid) override; int comments(const QString &guid) const override; QString commentsLink(const QString &guid) const override; void setCommentsLink(const QString &guid, const QString &commentsLink) override; void setComments(const QString &guid, int comments) override; bool guidIsHash(const QString &guid) const override; void setGuidIsHash(const QString &guid, bool isHash) override; bool guidIsPermaLink(const QString &guid) const override; void setGuidIsPermaLink(const QString &guid, bool isPermaLink) override; uint hash(const QString &guid) const override; void setHash(const QString &guid, uint hash) override; void setDeleted(const QString &guid) override; QString link(const QString &guid) const override; void setLink(const QString &guid, const QString &link) override; - uint pubDate(const QString &guid) const override; - void setPubDate(const QString &guid, uint pubdate) override; + QDateTime pubDate(const QString &guid) const override; + void setPubDate(const QString &guid, const QDateTime &pubdate) override; int status(const QString &guid) const override; void setStatus(const QString &guid, int status) override; QString title(const QString &guid) const override; void setTitle(const QString &guid, const QString &title) override; QString description(const QString &guid) const override; void setDescription(const QString &guid, const QString &description) override; QString content(const QString &guid) const override; void setContent(const QString &guid, const QString &content) override; void setEnclosure(const QString &guid, const QString &url, const QString &type, int length) override; void removeEnclosure(const QString &guid) override; void enclosure(const QString &guid, bool &hasEnclosure, QString &url, QString &type, int &length) const override; void setAuthorName(const QString &guid, const QString &name) override; void setAuthorUri(const QString &guid, const QString &uri) override; void setAuthorEMail(const QString &guid, const QString &email) override; QString authorName(const QString &guid) const override; QString authorUri(const QString &guid) const override; QString authorEMail(const QString &guid) const override; void close() override; void commit() override; void rollback() override; private: void markDirty(); /** finds article by guid, returns -1 if not in archive **/ int findArticle(const QString &guid) const; void setTotalCount(int total); class FeedStorageMK4ImplPrivate; FeedStorageMK4ImplPrivate *d; }; } // namespace Backend } // namespace Akregator #endif // AKREGATOR_BACKEND_FEEDSTORAGEMK4IMPL_H diff --git a/src/article.cpp b/src/article.cpp index 6b808dbc..a11ecd78 100644 --- a/src/article.cpp +++ b/src/article.cpp @@ -1,561 +1,561 @@ /* This file is part of Akregator. Copyright (C) 2004 Stanislav Karchebny 2005 Frank Osterfeld 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. As a special exception, permission is given to link this program with any edition of Qt, and distribute the resulting executable, without including the source code for Qt in the source distribution. */ #include "article.h" #include "feed.h" #include "feedstorage.h" #include "shared.h" #include "storage.h" #include "utils.h" #include #include #include #include #include #include "akregator_debug.h" #include #include using namespace Syndication; namespace { QString buildTitle(const QString &description) { QString s = description; if (description.trimmed().isEmpty()) { return QString(); } int i = s.indexOf(QLatin1Char('>'), 500); /*avoid processing too much */ if (i != -1) { s = s.left(i + 1); } QRegExp rx(QStringLiteral("(<([^\\s>]*)(?:[^>]*)>)[^<]*"), Qt::CaseInsensitive); QString tagName, toReplace, replaceWith; while (rx.indexIn(s) != -1) { tagName = rx.cap(2); if (tagName == QLatin1String("SCRIPT") || tagName == QLatin1String("script")) { toReplace = rx.cap(0); // strip tag AND tag contents } else if (tagName.startsWith(QLatin1String("br")) || tagName.startsWith(QLatin1String("BR"))) { toReplace = rx.cap(1); replaceWith = QLatin1Char(' '); } else { toReplace = rx.cap(1); // strip just tag } s = s.replace(s.indexOf(toReplace), toReplace.length(), replaceWith); // do the deed } if (s.length() > 90) { s = s.left(90) + QLatin1String("..."); } return s.simplified(); } } namespace Akregator { struct Article::Private : public Shared { Private(); Private(const QString &guid, Feed *feed, Backend::FeedStorage *archive); Private(const ItemPtr &article, Feed *feed, Backend::FeedStorage *archive); /** The status of the article is stored in an int, the bits having the following meaning: 0000 0001 Deleted 0000 0010 Trash 0000 0100 New 0000 1000 Read 0001 0000 Keep */ enum Status { Deleted = 0x01, Trash = 0x02, New = 0x04, Read = 0x08, Keep = 0x10 }; Feed *feed = nullptr; QString guid; Backend::FeedStorage *archive = nullptr; int status; uint hash; QDateTime pubDate; mutable QSharedPointer enclosure; }; namespace { class EnclosureImpl : public Enclosure { public: EnclosureImpl(const QString &url, const QString &type, uint length) : m_url(url) , m_type(type) , m_length(length) { } QString url() const override { return m_url; } QString type() const override { return m_type; } QString title() const override { return m_title; } uint length() const override { return m_length; } uint duration() const override { return 0; } bool isNull() const override { return m_url.isNull(); } private: QString m_url; QString m_type; QString m_title; uint m_length; }; } Article::Private::Private() : feed(nullptr) , archive(nullptr) , status(0) , hash(0) , pubDate(QDateTime::fromTime_t(1)) { } Article::Private::Private(const QString &guid_, Feed *feed_, Backend::FeedStorage *archive_) : feed(feed_) , guid(guid_) , archive(archive_) , status(archive->status(guid)) , hash(archive->hash(guid)) - , pubDate(QDateTime::fromTime_t(archive->pubDate(guid))) + , pubDate(archive->pubDate(guid)) { } Article::Private::Private(const ItemPtr &article, Feed *feed_, Backend::FeedStorage *archive_) : feed(feed_) , archive(archive_) , status(New) , hash(0) { Q_ASSERT(archive); const QList authorList = article->authors(); QString author; const PersonPtr firstAuthor = !authorList.isEmpty() ? authorList.first() : PersonPtr(); hash = Utils::calcHash(article->title() + article->description() + article->content() + article->link() + author); guid = article->id(); if (!archive->contains(guid)) { archive->addEntry(guid); archive->setHash(guid, hash); QString title = article->title(); if (title.isEmpty()) { title = buildTitle(article->description()); } archive->setTitle(guid, title); archive->setContent(guid, article->content()); archive->setDescription(guid, article->description()); archive->setLink(guid, article->link()); //archive->setComments(guid, article.comments()); //archive->setCommentsLink(guid, article.commentsLink().url()); archive->setGuidIsPermaLink(guid, false); archive->setGuidIsHash(guid, guid.startsWith(QLatin1String("hash:"))); const time_t datePublished = article->datePublished(); if (datePublished > 0) { pubDate.setTime_t(datePublished); } else { pubDate = QDateTime::currentDateTime(); } - archive->setPubDate(guid, pubDate.toTime_t()); + archive->setPubDate(guid, pubDate); if (firstAuthor) { archive->setAuthorName(guid, firstAuthor->name()); archive->setAuthorUri(guid, firstAuthor->uri()); archive->setAuthorEMail(guid, firstAuthor->email()); } const QList encs = article->enclosures(); if (!encs.isEmpty()) { archive->setEnclosure(guid, encs[0]->url(), encs[0]->type(), encs[0]->length()); } } else { // always update comments count, as it's not used for hash calculation //archive->setComments(guid, article.comments()); if (hash != archive->hash(guid)) { //article is in archive, was it modified? // if yes, update - pubDate.setTime_t(archive->pubDate(guid)); + pubDate = archive->pubDate(guid); archive->setHash(guid, hash); QString title = article->title(); if (title.isEmpty()) { title = buildTitle(article->description()); } archive->setTitle(guid, title); archive->setDescription(guid, article->description()); archive->setContent(guid, article->content()); archive->setLink(guid, article->link()); if (firstAuthor) { archive->setAuthorName(guid, firstAuthor->name()); archive->setAuthorUri(guid, firstAuthor->uri()); archive->setAuthorEMail(guid, firstAuthor->email()); } //archive->setCommentsLink(guid, article.commentsLink()); } } const QList encs = article->enclosures(); if (!encs.isEmpty()) { archive->setEnclosure(guid, encs[0]->url(), encs[0]->type(), encs[0]->length()); } } Article::Article() : d(new Private) { } Article::Article(const QString &guid, Feed *feed) : d(new Private(guid, feed, feed->storage()->archiveFor(feed->xmlUrl()))) { } Article::Article(const ItemPtr &article, Feed *feed) : d(new Private(article, feed, feed->storage()->archiveFor(feed->xmlUrl()))) { } Article::Article(const ItemPtr &article, Backend::FeedStorage *archive) : d(new Private(article, nullptr, archive)) { } bool Article::isNull() const { return d->archive == nullptr; // TODO: use proper null state } void Article::offsetPubDate(int secs) { d->pubDate = d->pubDate.addSecs(secs); - d->archive->setPubDate(d->guid, d->pubDate.toTime_t()); + d->archive->setPubDate(d->guid, d->pubDate); } void Article::setDeleted() { if (isDeleted()) { return; } setStatus(Read); d->status = Private::Deleted | Private::Read; d->archive->setStatus(d->guid, d->status); d->archive->setDeleted(d->guid); if (d->feed) { d->feed->setArticleDeleted(*this); } } bool Article::isDeleted() const { return (d->status & Private::Deleted) != 0; } Article::Article(const Article &other) : d(other.d) { d->ref(); } Article::~Article() { if (d->deref()) { delete d; d = nullptr; } } Article &Article::operator=(const Article &other) { Article copy(other); swap(copy); return *this; } bool Article::operator<(const Article &other) const { return pubDate() > other.pubDate() || (pubDate() == other.pubDate() && guid() < other.guid()); } bool Article::operator<=(const Article &other) const { return pubDate() > other.pubDate() || *this == other; } bool Article::operator>(const Article &other) const { return pubDate() < other.pubDate() || (pubDate() == other.pubDate() && guid() > other.guid()); } bool Article::operator>=(const Article &other) const { return pubDate() > other.pubDate() || *this == other; } bool Article::operator==(const Article &other) const { return d->guid == other.guid(); } bool Article::operator!=(const Article &other) const { return d->guid != other.guid(); } int Article::status() const { if ((d->status & Private::Read) != 0) { return Read; } if ((d->status & Private::New) != 0) { return New; } return Unread; } void Article::setStatus(int stat) { int oldStatus = status(); if (oldStatus != stat) { switch (stat) { case Read: d->status = (d->status | Private::Read) & ~Private::New; break; case Unread: d->status = (d->status & ~Private::Read) & ~Private::New; break; case New: d->status = (d->status | Private::New) & ~Private::Read; break; } if (d->archive) { d->archive->setStatus(d->guid, d->status); } if (d->feed) { d->feed->setArticleChanged(*this, oldStatus, stat != Read); } } } QString Article::title() const { QString str; if (d->archive) { str = d->archive->title(d->guid); } return str; } QString Article::authorName() const { QString str; if (d->archive) { str = d->archive->authorName(d->guid); } return str; } QString Article::authorEMail() const { QString str; if (d->archive) { str = d->archive->authorEMail(d->guid); } return str; } QString Article::authorUri() const { QString str; if (d->archive) { str = d->archive->authorUri(d->guid); } return str; } QString Article::authorShort() const { const QString name = authorName(); if (!name.isEmpty()) { return name; } const QString email = authorEMail(); if (!email.isEmpty()) { return email; } const QString uri = authorUri(); if (!uri.isEmpty()) { return uri; } return QString(); } QString Article::authorAsHtml() const { const QString name = authorName(); const QString email = authorEMail(); if (!email.isEmpty()) { if (!name.isEmpty()) { return QStringLiteral("%2").arg(email, name); } else { return QStringLiteral("%1").arg(email); } } const QString uri = authorUri(); if (!name.isEmpty()) { if (!uri.isEmpty()) { return QStringLiteral("%2").arg(uri, name); } else { return name; } } if (!uri.isEmpty()) { return QStringLiteral("%1").arg(uri); } return QString(); } QUrl Article::link() const { return QUrl(d->archive->link(d->guid)); } QString Article::description() const { return d->archive->description(d->guid); } QString Article::content(ContentOption opt) const { const QString cnt = d->archive->content(d->guid); return opt == ContentAndOnlyContent ? cnt : (!cnt.isEmpty() ? cnt : description()); } QString Article::guid() const { return d->guid; } QUrl Article::commentsLink() const { return QUrl(d->archive->commentsLink(d->guid)); } int Article::comments() const { return d->archive->comments(d->guid); } bool Article::guidIsPermaLink() const { return d->archive->guidIsPermaLink(d->guid); } bool Article::guidIsHash() const { return d->archive->guidIsHash(d->guid); } uint Article::hash() const { return d->hash; } bool Article::keep() const { return (d->status & Private::Keep) != 0; } void Article::setKeep(bool keep) { d->status = keep ? (d->status | Private::Keep) : (d->status & ~Private::Keep); d->archive->setStatus(d->guid, d->status); if (d->feed) { d->feed->setArticleChanged(*this); } } Feed *Article::feed() const { return d->feed; } QDateTime Article::pubDate() const { return d->pubDate; } QSharedPointer Article::enclosure() const { if (!d->enclosure) { QString url; QString type; int length; bool hasEnc; d->archive->enclosure(d->guid, hasEnc, url, type, length); if (hasEnc) { d->enclosure.reset(new EnclosureImpl(url, type, static_cast(length))); } else { d->enclosure.reset(new EnclosureImpl(QString(), QString(), 0)); } } return d->enclosure; } } // namespace Akregator diff --git a/src/dummystorage/feedstoragedummyimpl.cpp b/src/dummystorage/feedstoragedummyimpl.cpp index 5f55aabf..208a345c 100644 --- a/src/dummystorage/feedstoragedummyimpl.cpp +++ b/src/dummystorage/feedstoragedummyimpl.cpp @@ -1,421 +1,422 @@ /* This file is part of Akregator. Copyright (C) 2005 Frank Osterfeld 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. As a special exception, permission is given to link this program with any edition of Qt, and distribute the resulting executable, without including the source code for Qt in the source distribution. */ #include "feedstoragedummyimpl.h" #include "storagedummyimpl.h" #include +#include #include #include #include #include #include namespace Akregator { namespace Backend { class FeedStorageDummyImpl::FeedStorageDummyImplPrivate { public: class Entry { public: Entry() : status(0) - , pubDate(0) + , pubDate() , hash(0) , guidIsHash(false) , guidIsPermaLink(false) { } StorageDummyImpl *mainStorage = nullptr; QString enclosureUrl; QString enclosureType; QString title; QString description; QString content; QString link; QString authorName; QString authorUri; QString authorEMail; QString commentsLink; int comments; int status; int enclosureLength; - uint pubDate; + QDateTime pubDate; uint hash; bool guidIsHash = false; bool guidIsPermaLink = false; bool hasEnclosure = false; }; QHash entries; Storage *mainStorage; QString url; }; FeedStorageDummyImpl::FeedStorageDummyImpl(const QString &url, StorageDummyImpl *main) : d(new FeedStorageDummyImplPrivate) { d->url = url; d->mainStorage = main; } FeedStorageDummyImpl::~FeedStorageDummyImpl() { delete d; d = nullptr; } void FeedStorageDummyImpl::commit() { } void FeedStorageDummyImpl::rollback() { } void FeedStorageDummyImpl::close() { } int FeedStorageDummyImpl::unread() const { return d->mainStorage->unreadFor(d->url); } void FeedStorageDummyImpl::setUnread(int unread) { d->mainStorage->setUnreadFor(d->url, unread); } int FeedStorageDummyImpl::totalCount() const { return d->mainStorage->totalCountFor(d->url); } void FeedStorageDummyImpl::setTotalCount(int total) { d->mainStorage->setTotalCountFor(d->url, total); } int FeedStorageDummyImpl::lastFetch() const { return d->mainStorage->lastFetchFor(d->url); } void FeedStorageDummyImpl::setLastFetch(int lastFetch) { d->mainStorage->setLastFetchFor(d->url, lastFetch); } QStringList FeedStorageDummyImpl::articles() const { return QStringList(d->entries.keys()); } void FeedStorageDummyImpl::addEntry(const QString &guid) { if (!d->entries.contains(guid)) { d->entries[guid] = FeedStorageDummyImplPrivate::Entry(); setTotalCount(totalCount() + 1); } } bool FeedStorageDummyImpl::contains(const QString &guid) const { return d->entries.contains(guid); } void FeedStorageDummyImpl::deleteArticle(const QString &guid) { if (!d->entries.contains(guid)) { return; } setDeleted(guid); d->entries.remove(guid); } int FeedStorageDummyImpl::comments(const QString &guid) const { return contains(guid) ? d->entries[guid].comments : 0; } QString FeedStorageDummyImpl::commentsLink(const QString &guid) const { return contains(guid) ? d->entries[guid].commentsLink : QString(); } bool FeedStorageDummyImpl::guidIsHash(const QString &guid) const { return contains(guid) ? d->entries[guid].guidIsHash : false; } bool FeedStorageDummyImpl::guidIsPermaLink(const QString &guid) const { return contains(guid) ? d->entries[guid].guidIsPermaLink : false; } uint FeedStorageDummyImpl::hash(const QString &guid) const { return contains(guid) ? d->entries[guid].hash : 0; } void FeedStorageDummyImpl::setDeleted(const QString &guid) { if (!contains(guid)) { return; } FeedStorageDummyImplPrivate::Entry entry = d->entries[guid]; entry.description.clear(); entry.content.clear(); entry.title.clear(); entry.link.clear(); entry.commentsLink.clear(); } QString FeedStorageDummyImpl::link(const QString &guid) const { return contains(guid) ? d->entries[guid].link : QString(); } -uint FeedStorageDummyImpl::pubDate(const QString &guid) const +QDateTime FeedStorageDummyImpl::pubDate(const QString &guid) const { - return contains(guid) ? d->entries[guid].pubDate : 0; + return contains(guid) ? d->entries[guid].pubDate : QDateTime(); } int FeedStorageDummyImpl::status(const QString &guid) const { return contains(guid) ? d->entries[guid].status : 0; } void FeedStorageDummyImpl::setStatus(const QString &guid, int status) { if (contains(guid)) { d->entries[guid].status = status; } } QString FeedStorageDummyImpl::title(const QString &guid) const { return contains(guid) ? d->entries[guid].title : QString(); } QString FeedStorageDummyImpl::description(const QString &guid) const { return contains(guid) ? d->entries[guid].description : QString(); } QString FeedStorageDummyImpl::content(const QString &guid) const { return contains(guid) ? d->entries[guid].content : QString(); } QString FeedStorageDummyImpl::authorName(const QString &guid) const { return contains(guid) ? d->entries[guid].authorName : QString(); } QString FeedStorageDummyImpl::authorUri(const QString &guid) const { return contains(guid) ? d->entries[guid].authorUri : QString(); } QString FeedStorageDummyImpl::authorEMail(const QString &guid) const { return contains(guid) ? d->entries[guid].authorEMail : QString(); } -void FeedStorageDummyImpl::setPubDate(const QString &guid, uint pubdate) +void FeedStorageDummyImpl::setPubDate(const QString &guid, const QDateTime &pubdate) { if (contains(guid)) { d->entries[guid].pubDate = pubdate; } } void FeedStorageDummyImpl::setGuidIsHash(const QString &guid, bool isHash) { if (contains(guid)) { d->entries[guid].guidIsHash = isHash; } } void FeedStorageDummyImpl::setLink(const QString &guid, const QString &link) { if (contains(guid)) { d->entries[guid].link = link; } } void FeedStorageDummyImpl::setHash(const QString &guid, uint hash) { if (contains(guid)) { d->entries[guid].hash = hash; } } void FeedStorageDummyImpl::setTitle(const QString &guid, const QString &title) { if (contains(guid)) { d->entries[guid].title = title; } } void FeedStorageDummyImpl::setDescription(const QString &guid, const QString &description) { if (contains(guid)) { d->entries[guid].description = description; } } void FeedStorageDummyImpl::setCommentsLink(const QString &guid, const QString &commentsLink) { if (contains(guid)) { d->entries[guid].commentsLink = commentsLink; } } void FeedStorageDummyImpl::setContent(const QString &guid, const QString &content) { if (contains(guid)) { d->entries[guid].content = content; } } void FeedStorageDummyImpl::setAuthorName(const QString &guid, const QString &author) { if (contains(guid)) { d->entries[guid].authorName = author; } } void FeedStorageDummyImpl::setAuthorUri(const QString &guid, const QString &author) { if (contains(guid)) { d->entries[guid].authorUri = author; } } void FeedStorageDummyImpl::setAuthorEMail(const QString &guid, const QString &author) { if (contains(guid)) { d->entries[guid].authorEMail = author; } } void FeedStorageDummyImpl::setComments(const QString &guid, int comments) { if (contains(guid)) { d->entries[guid].comments = comments; } } void FeedStorageDummyImpl::setGuidIsPermaLink(const QString &guid, bool isPermaLink) { if (contains(guid)) { d->entries[guid].guidIsPermaLink = isPermaLink; } } void FeedStorageDummyImpl::add(FeedStorage *source) { QStringList articles = source->articles(); for (QStringList::ConstIterator it = articles.constBegin(); it != articles.constEnd(); ++it) { copyArticle(*it, source); } setUnread(source->unread()); setLastFetch(source->lastFetch()); setTotalCount(source->totalCount()); } void FeedStorageDummyImpl::copyArticle(const QString &guid, FeedStorage *source) { if (!contains(guid)) { addEntry(guid); } setComments(guid, source->comments(guid)); setCommentsLink(guid, source->commentsLink(guid)); setDescription(guid, source->description(guid)); setContent(guid, source->content(guid)); setGuidIsHash(guid, source->guidIsHash(guid)); setGuidIsPermaLink(guid, source->guidIsPermaLink(guid)); setHash(guid, source->hash(guid)); setLink(guid, source->link(guid)); setPubDate(guid, source->pubDate(guid)); setStatus(guid, source->status(guid)); setTitle(guid, source->title(guid)); } void FeedStorageDummyImpl::clear() { d->entries.clear(); setUnread(0); setTotalCount(0); } void FeedStorageDummyImpl::setEnclosure(const QString &guid, const QString &url, const QString &type, int length) { if (contains(guid)) { FeedStorageDummyImplPrivate::Entry entry = d->entries[guid]; entry.hasEnclosure = true; entry.enclosureUrl = url; entry.enclosureType = type; entry.enclosureLength = length; } } void FeedStorageDummyImpl::removeEnclosure(const QString &guid) { if (contains(guid)) { FeedStorageDummyImplPrivate::Entry entry = d->entries[guid]; entry.hasEnclosure = false; entry.enclosureUrl.clear(); entry.enclosureType.clear(); entry.enclosureLength = -1; } } void FeedStorageDummyImpl::enclosure(const QString &guid, bool &hasEnclosure, QString &url, QString &type, int &length) const { if (contains(guid)) { FeedStorageDummyImplPrivate::Entry entry = d->entries[guid]; hasEnclosure = entry.hasEnclosure; url = entry.enclosureUrl; type = entry.enclosureType; length = entry.enclosureLength; } else { hasEnclosure = false; url.clear(); type.clear(); length = -1; } } } // namespace Backend } // namespace Akregator diff --git a/src/dummystorage/feedstoragedummyimpl.h b/src/dummystorage/feedstoragedummyimpl.h index 5a06adf0..df27b239 100644 --- a/src/dummystorage/feedstoragedummyimpl.h +++ b/src/dummystorage/feedstoragedummyimpl.h @@ -1,102 +1,102 @@ /* This file is part of Akregator. Copyright (C) 2005 Frank Osterfeld 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. As a special exception, permission is given to link this program with any edition of Qt, and distribute the resulting executable, without including the source code for Qt in the source distribution. */ #ifndef AKREGATOR_BACKEND_FEEDSTORAGEDUMMYIMPL_H #define AKREGATOR_BACKEND_FEEDSTORAGEDUMMYIMPL_H #include "feedstorage.h" #include namespace Akregator { namespace Backend { class StorageDummyImpl; class FeedStorageDummyImpl : public FeedStorage { public: FeedStorageDummyImpl(const QString &url, StorageDummyImpl *main); ~FeedStorageDummyImpl() override; void add(FeedStorage *source) override; void copyArticle(const QString &guid, FeedStorage *source) override; void clear() override; int unread() const override; void setUnread(int unread) override; int totalCount() const override; int lastFetch() const override; void setLastFetch(int lastFetch) override; QStringList articles() const override; bool contains(const QString &guid) const override; void addEntry(const QString &guid) override; void deleteArticle(const QString &guid) override; int comments(const QString &guid) const override; QString commentsLink(const QString &guid) const override; void setCommentsLink(const QString &guid, const QString &commentsLink) override; void setComments(const QString &guid, int comments) override; bool guidIsHash(const QString &guid) const override; void setGuidIsHash(const QString &guid, bool isHash) override; bool guidIsPermaLink(const QString &guid) const override; void setGuidIsPermaLink(const QString &guid, bool isPermaLink) override; uint hash(const QString &guid) const override; void setHash(const QString &guid, uint hash) override; void setDeleted(const QString &guid) override; QString link(const QString &guid) const override; void setLink(const QString &guid, const QString &link) override; - uint pubDate(const QString &guid) const override; - void setPubDate(const QString &guid, uint pubdate) override; + QDateTime pubDate(const QString &guid) const override; + void setPubDate(const QString &guid, const QDateTime & pubdate) override; int status(const QString &guid) const override; void setStatus(const QString &guid, int status) override; QString title(const QString &guid) const override; void setTitle(const QString &guid, const QString &title) override; QString description(const QString &guid) const override; void setDescription(const QString &guid, const QString &description) override; QString content(const QString &guid) const override; void setContent(const QString &guid, const QString &content) override; void setEnclosure(const QString &guid, const QString &url, const QString &type, int length) override; void removeEnclosure(const QString &guid) override; void enclosure(const QString &guid, bool &hasEnclosure, QString &url, QString &type, int &length) const override; void setAuthorName(const QString &guid, const QString &authorName) override; void setAuthorUri(const QString &guid, const QString &authorUri) override; void setAuthorEMail(const QString &guid, const QString &authorEMail) override; QString authorName(const QString &guid) const override; QString authorUri(const QString &guid) const override; QString authorEMail(const QString &guid) const override; void close() override; void commit() override; void rollback() override; private: /** finds article by guid, returns -1 if not in archive **/ int findArticle(const QString &guid) const; void setTotalCount(int total); class FeedStorageDummyImplPrivate; FeedStorageDummyImplPrivate *d; }; } // namespace Backend } // namespace Akregator #endif // AKREGATOR_FEEDSTORAGEDUMMYIMPL_H