work on ical
This commit is contained in:
parent
b49b7f470b
commit
0ad4b25522
10 changed files with 211 additions and 29 deletions
|
@ -145,8 +145,8 @@ QStringList TextFactory::dateTimePatterns() {
|
|||
<< QSL("ddd, d MMM yyyy HH:mm:ss") << QSL("dd MMM yyyy hh:mm:ss") << QSL("dd MMM yyyy")
|
||||
<< QSL("yyyy-MM-dd HH:mm:ss.z") << QSL("yyyy-MM-dd") << QSL("yyyy") << QSL("yyyy-MM")
|
||||
<< QSL("yyyy-MM-dd") << QSL("yyyy-MM-ddThh:mm") << QSL("yyyy-MM-ddThh:mm:ss")
|
||||
<< QSL("d MMM yyyy HH:mm:ss") << QSL("hh:mm:ss") << QSL("h:m:s AP") << QSL("h:mm") << QSL("H:mm")
|
||||
<< QSL("h:m") << QSL("h.m");
|
||||
<< QSL("d MMM yyyy HH:mm:ss") << QSL("yyyyMMddThhmmss") << QSL("yyyyMMdd") << QSL("hh:mm:ss")
|
||||
<< QSL("h:m:s AP") << QSL("h:mm") << QSL("H:mm") << QSL("h:m") << QSL("h.m");
|
||||
}
|
||||
|
||||
QString TextFactory::encrypt(const QString& text, quint64 key) {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "services/standard/standardfeed.h"
|
||||
|
||||
#include "services/standard/parsers/atomparser.h"
|
||||
#include "services/standard/parsers/icalparser.h"
|
||||
#include "services/standard/parsers/jsonparser.h"
|
||||
#include "services/standard/parsers/rdfparser.h"
|
||||
#include "services/standard/parsers/rssparser.h"
|
||||
|
@ -31,7 +32,12 @@ FormDiscoverFeeds::FormDiscoverFeeds(ServiceRoot* service_root,
|
|||
|
||||
GuiUtilities::applyDialogProperties(*this, qApp->icons()->fromTheme(QSL("application-rss+xml")));
|
||||
|
||||
m_parsers = {new AtomParser({}), new RssParser({}), new RdfParser({}), new JsonParser({}), new SitemapParser({})};
|
||||
m_parsers = {new AtomParser({}),
|
||||
new RssParser({}),
|
||||
new RdfParser({}),
|
||||
new IcalParser({}),
|
||||
new JsonParser({}),
|
||||
new SitemapParser({})};
|
||||
|
||||
m_btnGoAdvanced = m_ui.m_buttonBox->addButton(tr("Switch to &advanced mode"), QDialogButtonBox::ButtonRole::NoRole);
|
||||
m_btnGoAdvanced
|
||||
|
|
|
@ -53,6 +53,8 @@ StandardFeedDetails::StandardFeedDetails(QWidget* parent) : QWidget(parent) {
|
|||
QVariant::fromValue(int(StandardFeed::Type::Rss0X)));
|
||||
m_ui.m_cmbType->addItem(StandardFeed::typeToString(StandardFeed::Type::Rss2X),
|
||||
QVariant::fromValue(int(StandardFeed::Type::Rss2X)));
|
||||
m_ui.m_cmbType->addItem(StandardFeed::typeToString(StandardFeed::Type::iCalendar),
|
||||
QVariant::fromValue(int(StandardFeed::Type::iCalendar)));
|
||||
m_ui.m_cmbType->addItem(StandardFeed::typeToString(StandardFeed::Type::Json),
|
||||
QVariant::fromValue(int(StandardFeed::Type::Json)));
|
||||
m_ui.m_cmbType->addItem(StandardFeed::typeToString(StandardFeed::Type::Sitemap),
|
||||
|
|
|
@ -21,6 +21,9 @@ class AtomParser : public FeedParser {
|
|||
const QString& content_type) const;
|
||||
|
||||
protected:
|
||||
virtual QDomNodeList xmlMessageElements();
|
||||
virtual QString feedAuthor() const;
|
||||
|
||||
virtual QString xmlMessageTitle(const QDomElement& msg_element) const;
|
||||
virtual QString xmlMessageDescription(const QDomElement& msg_element) const;
|
||||
virtual QDateTime xmlMessageDateCreated(const QDomElement& msg_element) const;
|
||||
|
@ -28,9 +31,7 @@ class AtomParser : public FeedParser {
|
|||
virtual QString xmlMessageUrl(const QDomElement& msg_element) const;
|
||||
virtual QList<Enclosure> xmlMessageEnclosures(const QDomElement& msg_element) const;
|
||||
virtual QList<MessageCategory> xmlMessageCategories(const QDomElement& msg_element) const;
|
||||
virtual QDomNodeList xmlMessageElements();
|
||||
virtual QString xmlMessageAuthor(const QDomElement& msg_element) const;
|
||||
virtual QString feedAuthor() const;
|
||||
|
||||
private:
|
||||
QString atomNamespace() const;
|
||||
|
|
|
@ -63,6 +63,19 @@ class FeedParser {
|
|||
virtual QList<MessageCategory> jsonMessageCategories(const QJsonObject& msg_element) const;
|
||||
virtual QString jsonMessageRawContents(const QJsonObject& msg_element) const;
|
||||
|
||||
/*
|
||||
// Objects.
|
||||
virtual QVariantList objMessageElements();
|
||||
virtual QString objMessageTitle(const QVariantMap& msg_element) const;
|
||||
virtual QString objMessageUrl(const QVariantMap& msg_element) const;
|
||||
virtual QString objMessageDescription(const QVariantMap& msg_element) const;
|
||||
virtual QString objMessageAuthor(const QVariantMap& msg_element) const;
|
||||
virtual QDateTime objMessageDateCreated(const QVariantMap& msg_element) const;
|
||||
virtual QString objMessageId(const QVariantMap& msg_element) const;
|
||||
virtual QList<Enclosure> objMessageEnclosures(const QVariantMap& msg_element) const;
|
||||
virtual QList<MessageCategory> objMessageCategories(const QVariantMap& msg_element) const;
|
||||
virtual QString objMessageRawContents(const QVariantMap& msg_element) const;
|
||||
*/
|
||||
protected:
|
||||
QList<Enclosure> xmlMrssGetEnclosures(const QDomElement& msg_element) const;
|
||||
QString xmlMrssTextFromPath(const QDomElement& msg_element, const QString& xml_path) const;
|
||||
|
|
|
@ -5,15 +5,58 @@
|
|||
#include "definitions/definitions.h"
|
||||
#include "exceptions/applicationexception.h"
|
||||
#include "exceptions/feedrecognizedbutfailedexception.h"
|
||||
#include "miscellaneous/application.h"
|
||||
#include "miscellaneous/settings.h"
|
||||
#include "miscellaneous/textfactory.h"
|
||||
#include "services/standard/definitions.h"
|
||||
|
||||
IcalParser::IcalParser(const QString& data) : FeedParser(data, DataType::Other) {}
|
||||
|
||||
IcalParser::~IcalParser() {}
|
||||
|
||||
QList<StandardFeed*> IcalParser::discoverFeeds(ServiceRoot* root, const QUrl& url, bool greedy) const {
|
||||
auto base_result = FeedParser::discoverFeeds(root, url, greedy);
|
||||
|
||||
if (!base_result.isEmpty()) {
|
||||
return base_result;
|
||||
}
|
||||
|
||||
QString my_url = url.toString();
|
||||
|
||||
// Test direct URL for a feed.
|
||||
int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt();
|
||||
QByteArray data;
|
||||
auto res = NetworkFactory::performNetworkOperation(my_url,
|
||||
timeout,
|
||||
{},
|
||||
data,
|
||||
QNetworkAccessManager::Operation::GetOperation,
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
root->networkProxy());
|
||||
|
||||
if (res.m_networkError == QNetworkReply::NetworkError::NoError) {
|
||||
try {
|
||||
// 1.
|
||||
auto guessed_feed = guessFeed(data, res.m_contentType);
|
||||
|
||||
guessed_feed.first->setSource(my_url);
|
||||
|
||||
return {guessed_feed.first};
|
||||
}
|
||||
catch (...) {
|
||||
qDebugNN << LOGSEC_CORE << QUOTE_W_SPACE(my_url) << "is not a direct feed file.";
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
QPair<StandardFeed*, QList<IconLocation>> IcalParser::guessFeed(const QByteArray& content,
|
||||
const QString& content_type) const {
|
||||
if (content_type == QSL("text/calendar") || content.contains('\n')) {
|
||||
if (content_type.contains(QSL("text/calendar")) || content.contains("\r\n")) {
|
||||
Icalendar calendar;
|
||||
|
||||
try {
|
||||
|
@ -27,7 +70,7 @@ QPair<StandardFeed*, QList<IconLocation>> IcalParser::guessFeed(const QByteArray
|
|||
QList<IconLocation> icon_possible_locations;
|
||||
|
||||
feed->setEncoding(QSL(DEFAULT_FEED_ENCODING));
|
||||
feed->setType(StandardFeed::Type::Atom10);
|
||||
feed->setType(StandardFeed::Type::iCalendar);
|
||||
feed->setTitle(calendar.title());
|
||||
|
||||
return QPair<StandardFeed*, QList<IconLocation>>(feed, icon_possible_locations);
|
||||
|
@ -37,10 +80,8 @@ QPair<StandardFeed*, QList<IconLocation>> IcalParser::guessFeed(const QByteArray
|
|||
}
|
||||
}
|
||||
|
||||
Icalendar::Icalendar() {}
|
||||
|
||||
Icalendar::Icalendar(const QByteArray& data) {
|
||||
processLines(data);
|
||||
Icalendar::Icalendar(const QByteArray& data) : FeedParser(QString::fromUtf8(data), FeedParser::DataType::Ical) {
|
||||
processLines(m_data);
|
||||
}
|
||||
|
||||
QString Icalendar::title() const {
|
||||
|
@ -51,9 +92,99 @@ void Icalendar::setTitle(const QString& title) {
|
|||
m_title = title;
|
||||
}
|
||||
|
||||
void Icalendar::processLines(const QByteArray& data) {
|
||||
QString str_data = QString::fromUtf8(data);
|
||||
void Icalendar::processLines(const QString& data) {
|
||||
QRegularExpression regex("^BEGIN:(\\w+)\\r$(.+?)^(BEGIN|END):\\w+",
|
||||
QRegularExpression::PatternOption::MultilineOption |
|
||||
QRegularExpression::PatternOption::DotMatchesEverythingOption);
|
||||
|
||||
QStringList str_blocks =
|
||||
str_data.remove(QRegularExpression("^END:\\w+$")).split(QRegularExpression(QSL("^BEGIN:\\w+$")));
|
||||
auto all_matches = regex.globalMatch(data);
|
||||
|
||||
while (all_matches.hasNext()) {
|
||||
auto match = all_matches.next();
|
||||
QString component = match.captured(1);
|
||||
QString body = match.captured(2);
|
||||
|
||||
if (component == QSL("VCALENDAR")) {
|
||||
processComponentCalendar(body);
|
||||
}
|
||||
|
||||
if (component == QSL("VEVENT")) {
|
||||
processComponentEvent(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Icalendar::processComponentCalendar(const QString& body) {
|
||||
auto tokenized = tokenizeBody(body);
|
||||
|
||||
setTitle(tokenized.value(QSL("X-WR-CALNAME")));
|
||||
}
|
||||
|
||||
void Icalendar::processComponentEvent(const QString& body) {
|
||||
auto tokenized = tokenizeBody(body);
|
||||
|
||||
EventComponent event;
|
||||
|
||||
event.setUid(tokenized.value(QSL("UID")));
|
||||
event.setTitle(tokenized.value(QSL("SUMMARY")));
|
||||
event.setDescription(tokenized.value(QSL("DESCRIPTION")));
|
||||
event.setCreated(TextFactory::parseDateTime(tokenized.value(QSL("CREATED"))));
|
||||
|
||||
m_components.append(event);
|
||||
}
|
||||
|
||||
QMap<QString, QString> Icalendar::tokenizeBody(const QString& body) const {
|
||||
QRegularExpression regex("^(?=[A-Z-]+:)", QRegularExpression::PatternOption::MultilineOption);
|
||||
auto all_matches = body.split(regex);
|
||||
QMap<QString, QString> res;
|
||||
|
||||
for (const QString& match : all_matches) {
|
||||
int sep = match.indexOf(':');
|
||||
QString property = match.left(sep).simplified();
|
||||
|
||||
if (property.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QString value = match.mid(sep + 1);
|
||||
|
||||
value = value.replace(QRegularExpression("\\r\\n\\s?"), QString());
|
||||
value = value.replace(QRegularExpression("\\r?\\n"), QSL("<br/>"));
|
||||
|
||||
res.insert(property, value);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
QString IcalendarComponent::uid() const {
|
||||
return m_uid;
|
||||
}
|
||||
|
||||
void IcalendarComponent::setUid(const QString& uid) {
|
||||
m_uid = uid;
|
||||
}
|
||||
|
||||
QString EventComponent::title() const {
|
||||
return m_title;
|
||||
}
|
||||
|
||||
void EventComponent::setTitle(const QString& title) {
|
||||
m_title = title;
|
||||
}
|
||||
|
||||
QString EventComponent::description() const {
|
||||
return m_description;
|
||||
}
|
||||
|
||||
void EventComponent::setDescription(const QString& description) {
|
||||
m_description = description;
|
||||
}
|
||||
|
||||
QDateTime EventComponent::created() const {
|
||||
return m_created;
|
||||
}
|
||||
|
||||
void EventComponent::setCreated(const QDateTime& created) {
|
||||
m_created = created;
|
||||
}
|
||||
|
|
|
@ -5,27 +5,46 @@
|
|||
|
||||
#include "services/standard/parsers/feedparser.h"
|
||||
|
||||
class IcalendarComponent {};
|
||||
|
||||
class EventComponent : public IcalendarComponent {};
|
||||
|
||||
class Icalendar {
|
||||
class IcalendarComponent {
|
||||
public:
|
||||
enum class ProcessingState {
|
||||
BeginCalendar,
|
||||
EndCalendar,
|
||||
BeginEvent,
|
||||
EndEvent
|
||||
}
|
||||
QString uid() const;
|
||||
void setUid(const QString& uid);
|
||||
|
||||
explicit Icalendar();
|
||||
explicit Icalendar(const QByteArray& data);
|
||||
private:
|
||||
QString m_uid;
|
||||
};
|
||||
|
||||
class EventComponent : public IcalendarComponent {
|
||||
public:
|
||||
QString title() const;
|
||||
void setTitle(const QString& title);
|
||||
|
||||
QString description() const;
|
||||
void setDescription(const QString& description);
|
||||
|
||||
QDateTime created() const;
|
||||
void setCreated(const QDateTime& created);
|
||||
|
||||
private:
|
||||
QString m_title;
|
||||
QString m_description;
|
||||
QDateTime m_created;
|
||||
};
|
||||
|
||||
class Icalendar : public FeedParser {
|
||||
public:
|
||||
explicit Icalendar(const QByteArray& data = {});
|
||||
|
||||
QString title() const;
|
||||
void setTitle(const QString& title);
|
||||
|
||||
private:
|
||||
void processLines(const QByteArray& data);
|
||||
void processLines(const QString& data);
|
||||
void processComponentCalendar(const QString& body);
|
||||
void processComponentEvent(const QString& body);
|
||||
|
||||
QDateTime parseDateTime(const QString& date_time) const;
|
||||
QMap<QString, QString> tokenizeBody(const QString& body) const;
|
||||
|
||||
private:
|
||||
QString m_title;
|
||||
|
@ -37,6 +56,8 @@ class IcalParser : public FeedParser {
|
|||
explicit IcalParser(const QString& data);
|
||||
virtual ~IcalParser();
|
||||
|
||||
virtual QList<StandardFeed*> discoverFeeds(ServiceRoot* root, const QUrl& url, bool greedy) const;
|
||||
|
||||
virtual QPair<StandardFeed*, QList<IconLocation>> guessFeed(const QByteArray& content,
|
||||
const QString& content_type) const;
|
||||
};
|
||||
|
|
|
@ -20,6 +20,7 @@ class JsonParser : public FeedParser {
|
|||
protected:
|
||||
virtual QString feedAuthor() const;
|
||||
virtual QJsonArray jsonMessageElements();
|
||||
|
||||
virtual QString jsonMessageTitle(const QJsonObject& msg_element) const;
|
||||
virtual QString jsonMessageUrl(const QJsonObject& msg_element) const;
|
||||
virtual QString jsonMessageDescription(const QJsonObject& msg_element) const;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#endif
|
||||
|
||||
#include "services/standard/parsers/atomparser.h"
|
||||
#include "services/standard/parsers/icalparser.h"
|
||||
#include "services/standard/parsers/jsonparser.h"
|
||||
#include "services/standard/parsers/rdfparser.h"
|
||||
#include "services/standard/parsers/rssparser.h"
|
||||
|
@ -347,6 +348,7 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type,
|
|||
parsers.append(QSharedPointer<FeedParser>(new AtomParser({})));
|
||||
parsers.append(QSharedPointer<FeedParser>(new RssParser({})));
|
||||
parsers.append(QSharedPointer<FeedParser>(new RdfParser({})));
|
||||
parsers.append(QSharedPointer<FeedParser>(new IcalParser({})));
|
||||
parsers.append(QSharedPointer<FeedParser>(new JsonParser({})));
|
||||
parsers.append(QSharedPointer<FeedParser>(new SitemapParser({})));
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "services/standard/gui/formstandardfeeddetails.h"
|
||||
#include "services/standard/gui/formstandardimportexport.h"
|
||||
#include "services/standard/parsers/atomparser.h"
|
||||
#include "services/standard/parsers/icalparser.h"
|
||||
#include "services/standard/parsers/jsonparser.h"
|
||||
#include "services/standard/parsers/rdfparser.h"
|
||||
#include "services/standard/parsers/rssparser.h"
|
||||
|
@ -340,6 +341,10 @@ QList<Message> StandardServiceRoot::obtainNewMessages(Feed* feed,
|
|||
messages = JsonParser(formatted_feed_contents).messages();
|
||||
break;
|
||||
|
||||
case StandardFeed::Type::iCalendar:
|
||||
messages = IcalParser(formatted_feed_contents).messages();
|
||||
break;
|
||||
|
||||
case StandardFeed::Type::Sitemap:
|
||||
messages = SitemapParser(formatted_feed_contents).messages();
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue