diff --git a/src/librssguard/CMakeLists.txt b/src/librssguard/CMakeLists.txt index fc27e1afc..f3cb5cc7e 100644 --- a/src/librssguard/CMakeLists.txt +++ b/src/librssguard/CMakeLists.txt @@ -416,6 +416,8 @@ set(SOURCES services/standard/parsers/atomparser.h services/standard/parsers/feedparser.cpp services/standard/parsers/feedparser.h + services/standard/parsers/icalparser.cpp + services/standard/parsers/icalparser.h services/standard/parsers/jsonparser.cpp services/standard/parsers/jsonparser.h services/standard/parsers/rdfparser.cpp diff --git a/src/librssguard/services/standard/parsers/feedparser.cpp b/src/librssguard/services/standard/parsers/feedparser.cpp index 809d79eec..8384f3329 100644 --- a/src/librssguard/services/standard/parsers/feedparser.cpp +++ b/src/librssguard/services/standard/parsers/feedparser.cpp @@ -13,13 +13,13 @@ #include -FeedParser::FeedParser(QString data, bool is_xml) - : m_isXml(is_xml), m_data(std::move(data)), m_mrssNamespace(QSL("http://search.yahoo.com/mrss/")) { +FeedParser::FeedParser(QString data, DataType is_xml) + : m_dataType(is_xml), m_data(std::move(data)), m_mrssNamespace(QSL("http://search.yahoo.com/mrss/")) { if (m_data.isEmpty()) { return; } - if (m_isXml) { + if (m_dataType == DataType::Xml) { // XML. QString error; @@ -27,7 +27,7 @@ FeedParser::FeedParser(QString data, bool is_xml) throw FeedFetchException(Feed::Status::ParsingError, QObject::tr("XML problem: %1").arg(error)); } } - else { + else if (m_dataType == DataType::Json) { // JSON. QJsonParseError err; @@ -50,7 +50,6 @@ QList FeedParser::discoverFeeds(ServiceRoot* root, const QUrl& ur if (QFile::exists(file_path)) { try { - // 1. auto guessed_feed = guessFeed(IOFactory::readFile(file_path), {}); guessed_feed.first->setSourceType(StandardFeed::SourceType::LocalFile); @@ -126,7 +125,7 @@ QList FeedParser::messages() { QDateTime current_time = QDateTime::currentDateTimeUtc(); // Pull out all messages. - if (m_isXml) { + if (m_dataType == DataType::Xml) { QDomNodeList messages_in_xml = xmlMessageElements(); for (int i = 0; i < messages_in_xml.size(); i++) { @@ -154,7 +153,7 @@ QList FeedParser::messages() { } } } - else { + else if (m_dataType == DataType::Json) { QJsonArray messages_in_json = jsonMessageElements(); for (int i = 0; i < messages_in_json.size(); i++) { diff --git a/src/librssguard/services/standard/parsers/feedparser.h b/src/librssguard/services/standard/parsers/feedparser.h index 56b5475dd..d8898d1ce 100644 --- a/src/librssguard/services/standard/parsers/feedparser.h +++ b/src/librssguard/services/standard/parsers/feedparser.h @@ -16,7 +16,14 @@ // Base class for all XML-based feed parsers. class FeedParser { public: - explicit FeedParser(QString data, bool is_xml = true); + enum class DataType { + Xml, + Json, + Ical, + Other + }; + + explicit FeedParser(QString data, DataType is_xml = DataType::Xml); virtual ~FeedParser(); // Returns list of absolute URLs of discovered feeds from provided base URL. @@ -66,7 +73,7 @@ class FeedParser { bool only_first) const; protected: - bool m_isXml; + DataType m_dataType; QString m_data; QDomDocument m_xml; QJsonDocument m_json; diff --git a/src/librssguard/services/standard/parsers/icalparser.cpp b/src/librssguard/services/standard/parsers/icalparser.cpp new file mode 100644 index 000000000..7cc3efa3d --- /dev/null +++ b/src/librssguard/services/standard/parsers/icalparser.cpp @@ -0,0 +1,59 @@ +// For license of this file, see /LICENSE.md. + +#include "services/standard/parsers/icalparser.h" + +#include "definitions/definitions.h" +#include "exceptions/applicationexception.h" +#include "exceptions/feedrecognizedbutfailedexception.h" +#include "services/standard/definitions.h" + +IcalParser::IcalParser(const QString& data) : FeedParser(data, DataType::Other) {} + +IcalParser::~IcalParser() {} + +QPair> IcalParser::guessFeed(const QByteArray& content, + const QString& content_type) const { + if (content_type == QSL("text/calendar") || content.contains('\n')) { + Icalendar calendar; + + try { + calendar = Icalendar(content); + } + catch (const ApplicationException& ex) { + throw FeedRecognizedButFailedException(QObject::tr("iCalendar error '%1'").arg(ex.message())); + } + + auto* feed = new StandardFeed(); + QList icon_possible_locations; + + feed->setEncoding(QSL(DEFAULT_FEED_ENCODING)); + feed->setType(StandardFeed::Type::Atom10); + feed->setTitle(calendar.title()); + + return QPair>(feed, icon_possible_locations); + } + else { + throw ApplicationException(QObject::tr("not an iCalendar")); + } +} + +Icalendar::Icalendar() {} + +Icalendar::Icalendar(const QByteArray& data) { + processLines(data); +} + +QString Icalendar::title() const { + return m_title; +} + +void Icalendar::setTitle(const QString& title) { + m_title = title; +} + +void Icalendar::processLines(const QByteArray& data) { + QString str_data = QString::fromUtf8(data); + + QStringList str_blocks = + str_data.remove(QRegularExpression("^END:\\w+$")).split(QRegularExpression(QSL("^BEGIN:\\w+$"))); +} diff --git a/src/librssguard/services/standard/parsers/icalparser.h b/src/librssguard/services/standard/parsers/icalparser.h new file mode 100644 index 000000000..21894f633 --- /dev/null +++ b/src/librssguard/services/standard/parsers/icalparser.h @@ -0,0 +1,44 @@ +// For license of this file, see /LICENSE.md. + +#ifndef ICALPARSER_H +#define ICALPARSER_H + +#include "services/standard/parsers/feedparser.h" + +class IcalendarComponent {}; + +class EventComponent : public IcalendarComponent {}; + +class Icalendar { + public: + enum class ProcessingState { + BeginCalendar, + EndCalendar, + BeginEvent, + EndEvent + } + + explicit Icalendar(); + explicit Icalendar(const QByteArray& data); + + QString title() const; + void setTitle(const QString& title); + + private: + void processLines(const QByteArray& data); + + private: + QString m_title; + QList m_components; +}; + +class IcalParser : public FeedParser { + public: + explicit IcalParser(const QString& data); + virtual ~IcalParser(); + + virtual QPair> guessFeed(const QByteArray& content, + const QString& content_type) const; +}; + +#endif // ICALPARSER_H diff --git a/src/librssguard/services/standard/parsers/jsonparser.cpp b/src/librssguard/services/standard/parsers/jsonparser.cpp index 02364299c..e9b602e53 100644 --- a/src/librssguard/services/standard/parsers/jsonparser.cpp +++ b/src/librssguard/services/standard/parsers/jsonparser.cpp @@ -15,7 +15,7 @@ #include #include -JsonParser::JsonParser(const QString& data) : FeedParser(data, false) {} +JsonParser::JsonParser(const QString& data) : FeedParser(data, DataType::Json) {} JsonParser::~JsonParser() {} diff --git a/src/librssguard/services/standard/standardfeed.cpp b/src/librssguard/services/standard/standardfeed.cpp index f1a0c0b9f..6c03aabe6 100644 --- a/src/librssguard/services/standard/standardfeed.cpp +++ b/src/librssguard/services/standard/standardfeed.cpp @@ -187,6 +187,9 @@ QString StandardFeed::typeToString(StandardFeed::Type type) { case Type::Sitemap: return QSL("Sitemap"); + case Type::iCalendar: + return QSL("iCalendar"); + case Type::Rss2X: default: return QSL("RSS 2.0/2.0.1"); diff --git a/src/librssguard/services/standard/standardfeed.h b/src/librssguard/services/standard/standardfeed.h index 0f3de58ae..758941bb5 100644 --- a/src/librssguard/services/standard/standardfeed.h +++ b/src/librssguard/services/standard/standardfeed.h @@ -37,7 +37,8 @@ class StandardFeed : public Feed { Rdf = 2, // Sometimes denoted as RSS 1.0. Atom10 = 3, Json = 4, - Sitemap = 5 + Sitemap = 5, + iCalendar = 6 }; explicit StandardFeed(RootItem* parent_item = nullptr);