Direly needed reformatting

This commit is contained in:
Jaidyn Ann 2020-12-30 22:07:54 -06:00
parent f46a53fdc5
commit 85923f2cc2
22 changed files with 839 additions and 547 deletions

View File

@ -29,17 +29,18 @@ APP_MIME_SIG = application/x-vnd.Pogger
# same name (source.c or source.cpp) are included from different directories. # same name (source.c or source.cpp) are included from different directories.
# Also note that spaces in folder names do not work well with this Makefile. # Also note that spaces in folder names do not work well with this Makefile.
SRCS = \ SRCS = \
src/Feed.cpp, \
src/Entry.cpp, \
src/AtomFeed.cpp, \
src/RssFeed.cpp, \
src/PrefWindow.cpp, \
src/ProtocolListener.cpp, \
src/Mimetypes.cpp, \
src/Config.cpp, \
src/Util.cpp, \
src/App.cpp, \ src/App.cpp, \
src/AtomFeed.cpp, \
src/Config.cpp, \
src/Entry.cpp, \
src/Feed.cpp, \
src/FeedView.cpp, \
src/Invocation.cpp \ src/Invocation.cpp \
src/MainWindow.cpp, \
src/Mimetypes.cpp, \
src/ProtocolListener.cpp, \
src/RssFeed.cpp, \
src/Util.cpp
# Specify the resource definition files to use. Full or relative paths can be # Specify the resource definition files to use. Full or relative paths can be
# used. # used.

View File

@ -112,5 +112,5 @@ Sry bby, i'm trying <3
BORING INFO BORING INFO
-------------------------------------------------- --------------------------------------------------
Pogger is under the MIT license. Pogger is under the MIT license.
https://git.xwx.moe/pogger.git https://git.feneas.org/detruota/pogger
jadedctrl@teknik.io jadedctrl@teknik.io

View File

@ -1,20 +1,28 @@
/*
* Copyright 2020, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#include "App.h"
#include <StorageKit.h> #include <StorageKit.h>
#include <String.h> #include <String.h>
#include <getopt.h> #include <getopt.h>
#include "AtomFeed.h" #include "AtomFeed.h"
#include "RssFeed.h"
#include "Feed.h"
#include "Entry.h"
#include "Mimetypes.h"
#include "Config.h" #include "Config.h"
#include "Util.h" #include "Entry.h"
#include "App.h" #include "Feed.h"
#include "MainWindow.h"
#include "Invocation.h" #include "Invocation.h"
#include "MainWindow.h"
#include "Mimetypes.h"
#include "RssFeed.h"
#include "Util.h"
int int
main ( int argc, char** argv ) main(int argc, char** argv)
{ {
App* app = new App(); App* app = new App();
usageMsg.ReplaceAll("%app%", "Pogger"); usageMsg.ReplaceAll("%app%", "Pogger");
@ -24,10 +32,10 @@ main ( int argc, char** argv )
app->cfg->Load(); app->cfg->Load();
if ( argc == 1 ) if (argc == 1)
app->Run(); app->Run();
else else
cliStart( argc, argv ); cliStart(argc, argv);
if ( app->cfg->will_save == true ) if ( app->cfg->will_save == true )
@ -36,25 +44,22 @@ main ( int argc, char** argv )
return 0; return 0;
} }
// -------------------------------------
void void
cliStart ( int argc, char** argv ) cliStart(int argc, char** argv)
{ {
invocation( argc, argv ); invocation(argc, argv);
((App*)be_app)->cfg->targetFeeds.DoForEach( &processFeed ); ((App*)be_app)->cfg->targetFeeds.DoForEach(&processFeed);
} }
App::App ( )
: BApplication("application/x-vnd.Pogger") App::App() : BApplication("application/x-vnd.Pogger")
{ {
MainWindow* mainWin = new MainWindow(); MainWindow* mainWin = new MainWindow();
mainWin->Show(); mainWin->Show();
} }
// ----------------------------------------------------------------------------
const char* configPath = "/boot/home/config/settings/Pogger/"; const char* configPath = "/boot/home/config/settings/Pogger/";
BString usageMsg = BString usageMsg =
"Usage: %app% [-hvDus] [-tT datetime] [-cCO path] \n" "Usage: %app% [-hvDus] [-tT datetime] [-cCO path] \n"

View File

@ -1,9 +1,16 @@
#ifndef APPP_H /*
#define APPP_H * Copyright 2020, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#ifndef APP_H
#define APP_H
#include <SupportDefs.h> #include <SupportDefs.h>
#include <Application.h> #include <Application.h>
#include "Config.h"
class Config;
class App : public BApplication class App : public BApplication
@ -13,14 +20,14 @@ public:
Config* cfg; Config* cfg;
}; };
// ----------------------------------------------------------------------------
int main ( int, char** ); int main ( int, char** );
void cliStart ( int, char** ); void cliStart ( int, char** );
// ----------------------------------------------------------------------------
extern const char* configPath; extern const char* configPath;
extern BString usageMsg; extern BString usageMsg;
#endif #endif

View File

@ -1,11 +1,19 @@
#include <tinyxml2.h> /*
#include "Entry.h" * Copyright 2020, Jaidyn Levesque <jadedctrl@teknik.io>
#include "App.h" * All rights reserved. Distributed under the terms of the MIT license.
#include "Config.h" */
#include "Util.h"
#include "AtomFeed.h" #include "AtomFeed.h"
AtomFeed::AtomFeed ( ) #include <tinyxml2.h>
#include "App.h"
#include "Config.h"
#include "Entry.h"
#include "Util.h"
AtomFeed::AtomFeed()
{ {
title = BString("Untitled Feed"); title = BString("Untitled Feed");
description = BString(""); description = BString("");
@ -15,32 +23,37 @@ AtomFeed::AtomFeed ( )
outputDir = ((App*)be_app)->cfg->outDir; outputDir = ((App*)be_app)->cfg->outDir;
} }
AtomFeed::AtomFeed ( Feed* feed ) : AtomFeed::AtomFeed()
{ SetCachePath( feed->GetCachePath() ); }
// ---------------------------------------------------------------------------- AtomFeed::AtomFeed(Feed* feed)
: AtomFeed::AtomFeed()
{
SetCachePath(feed->GetCachePath());
}
void void
AtomFeed::Parse ( ) AtomFeed::Parse ()
{ {
entries = BList(); entries = BList();
tinyxml2::XMLDocument xml; tinyxml2::XMLDocument xml;
xml.LoadFile( GetCachePath().String() ); xml.LoadFile(GetCachePath().String());
Feed::Parse(); Feed::Parse();
tinyxml2::XMLElement* xfeed = xml.FirstChildElement("feed"); tinyxml2::XMLElement* xfeed = xml.FirstChildElement("feed");
RootParse( xfeed ); RootParse(xfeed);
ParseEntries( xfeed ); ParseEntries(xfeed);
BFile* feedFile = new BFile( GetCachePath().String(), B_READ_WRITE ); BFile* feedFile = new BFile(GetCachePath().String(), B_READ_WRITE);
time_t tt_lastDate = lastDate.Time_t(); time_t tt_lastDate = lastDate.Time_t();
feedFile->WriteAttr( "LastDate", B_TIME_TYPE, 0, &tt_lastDate, sizeof(time_t) ); feedFile->WriteAttr("LastDate", B_TIME_TYPE, 0, &tt_lastDate,
sizeof(time_t));
} }
void void
AtomFeed::RootParse( tinyxml2::XMLElement* xfeed ) AtomFeed::RootParse(tinyxml2::XMLElement* xfeed)
{ {
tinyxml2::XMLElement* xauthor = xfeed->FirstChildElement("author"); tinyxml2::XMLElement* xauthor = xfeed->FirstChildElement("author");
tinyxml2::XMLElement* xentry = xfeed->FirstChildElement("entry"); tinyxml2::XMLElement* xentry = xfeed->FirstChildElement("entry");
@ -49,70 +62,80 @@ AtomFeed::RootParse( tinyxml2::XMLElement* xfeed )
bool set = false; bool set = false;
SetTitle( xfeed->FirstChildElement("title") ); SetTitle(xfeed->FirstChildElement("title"));
SetDesc( xfeed->FirstChildElement("description") ); SetDesc( xfeed->FirstChildElement("description"));
set = SetDate( xfeed->FirstChildElement("updated") ); set = SetDate(xfeed->FirstChildElement("updated"));
if ( !set ) set = SetDate( xfeed->FirstChildElement("published") ); if (!set)
if ( !set && xentry ) set = SetDate( xentry->FirstChildElement("updated") ); set = SetDate(xfeed->FirstChildElement("published"));
if ( !set && xentry ) set = SetDate( xentry->FirstChildElement("published") ); if (!set && xentry)
set = SetDate(xentry->FirstChildElement("updated"));
if (!set && xentry)
set = SetDate(xentry->FirstChildElement("published"));
set = SetHomeUrl( xlink->Attribute( "href" ) ); set = SetHomeUrl(xlink->Attribute("href"));
if ( !set && xauthor ) set = SetHomeUrl( xauthor->FirstChildElement("uri") ); if (!set && xauthor)
if ( !set && xauthlink ) set = SetHomeUrl( xauthlink->Attribute( "href" ) ); set = SetHomeUrl(xauthor->FirstChildElement("uri"));
if (!set && xauthlink)
set = SetHomeUrl(xauthlink->Attribute("href"));
if ( ((App*)be_app)->cfg->verbose ) if (((App*)be_app)->cfg->verbose)
printf("Channel '%s' at '%s':\n", title.String(), homeUrl.String()); printf("Channel '%s' at '%s':\n", title.String(), homeUrl.String());
} }
void void
AtomFeed::EntryParse ( tinyxml2::XMLElement* xentry ) AtomFeed::EntryParse(tinyxml2::XMLElement* xentry)
{ {
Entry* newEntry= (Entry*)malloc( sizeof(Entry) ); Entry* newEntry = (Entry*)malloc(sizeof(Entry));
newEntry = new Entry( outputDir ); newEntry = new Entry(outputDir);
tinyxml2::XMLElement* xcontent = xentry->FirstChildElement("content"); tinyxml2::XMLElement* xcontent = xentry->FirstChildElement("content");
tinyxml2::XMLElement* xmedia = xentry->FirstChildElement("media:group"); tinyxml2::XMLElement* xmedia = xentry->FirstChildElement("media:group");
tinyxml2::XMLPrinter xprinter; tinyxml2::XMLPrinter xprinter;
newEntry->SetTitle( xentry->FirstChildElement("title") ); newEntry->SetTitle(xentry->FirstChildElement("title"));
newEntry->SetPostUrl( xentry->FirstChildElement("link")->Attribute("href") ); newEntry->SetPostUrl(xentry->FirstChildElement("link")->Attribute("href"));
newEntry->SetFeedTitle( title ); newEntry->SetFeedTitle(title);
bool set = false; bool set = false;
set = newEntry->SetDesc( xentry->FirstChildElement("summary") ); set = newEntry->SetDesc(xentry->FirstChildElement("summary"));
if ( !set ) set = newEntry->SetDesc( xentry->FirstChildElement("description")); if (!set)
if ( !set && xmedia ) set = newEntry->SetDesc( xmedia->FirstChildElement("media:description")); set = newEntry->SetDesc(xentry->FirstChildElement("description"));
if (!set && xmedia)
set = newEntry->SetDesc(xmedia->FirstChildElement("media:description"));
set = newEntry->SetDate( xentry->FirstChildElement("updated") ); set = newEntry->SetDate(xentry->FirstChildElement("updated"));
if ( !set ) set = newEntry->SetDate( xentry->FirstChildElement("published") ); if (!set)
set = newEntry->SetDate(xentry->FirstChildElement("published"));
if ( lastDate == NULL || lastDate < newEntry->date ) if (lastDate == NULL || lastDate < newEntry->date)
lastDate = newEntry->date; lastDate = newEntry->date;
if ( xcontent ) { if (xcontent) {
xcontent->Accept( &xprinter ); xcontent->Accept(&xprinter);
newEntry->SetContent( xprinter.CStr() ); newEntry->SetContent(xprinter.CStr());
} }
AddEntry( newEntry ); AddEntry(newEntry);
} }
void void
AtomFeed::ParseEntries ( tinyxml2::XMLElement* xfeed ) AtomFeed::ParseEntries(tinyxml2::XMLElement* xfeed)
{ {
tinyxml2::XMLElement* xentry; tinyxml2::XMLElement* xentry;
xentry = xfeed->FirstChildElement("entry"); xentry = xfeed->FirstChildElement("entry");
int entryCount = xmlCountSiblings( xentry, "entry" ); int entryCount = xmlCountSiblings(xentry, "entry");
entries = BList(entryCount); entries = BList(entryCount);
if ( ((App*)be_app)->cfg->verbose ) if (((App*)be_app)->cfg->verbose)
printf("\t-%i entries-\n", entryCount); printf("\t-%i entries-\n", entryCount);
while ( xentry ) { while (xentry) {
EntryParse( xentry ); EntryParse(xentry);
xentry = xentry->NextSiblingElement("entry"); xentry = xentry->NextSiblingElement("entry");
} }
} }

View File

@ -1,23 +1,27 @@
/*
* Copyright 2020, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#ifndef ATOM_FEED_H #ifndef ATOM_FEED_H
#define ATOM_FEED_H #define ATOM_FEED_H
#include <tinyxml2.h> #include <tinyxml2.h>
#include <DateTime.h>
#include <String.h>
#include <List.h>
#include <Url.h>
#include "Config.h"
#include "Feed.h" #include "Feed.h"
class AtomFeed: public Feed { class AtomFeed: public Feed {
public: public:
AtomFeed ( ); AtomFeed();
AtomFeed ( Feed* ); AtomFeed(Feed*);
void Parse ( ); void Parse();
void RootParse ( tinyxml2::XMLElement* ); void RootParse(tinyxml2::XMLElement*);
void EntryParse ( tinyxml2::XMLElement* ); void EntryParse(tinyxml2::XMLElement*);
void ParseEntries ( tinyxml2::XMLElement* ); void ParseEntries(tinyxml2::XMLElement*);
}; };
#endif #endif

View File

@ -1,15 +1,24 @@
#include <iostream> /*
#include <String.h> * Copyright 2020, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#include "Config.h" #include "Config.h"
Config::Config () { #include <String.h>
#include <iostream>
Config::Config() {
verbose = false; verbose = false;
daemon = true; daemon = true;
will_save = false; will_save = false;
updateFeeds = false; updateFeeds = false;
} }
Config::Config ( Config* cfg ) {
Config::Config(Config* cfg) {
verbose = cfg->verbose; verbose = cfg->verbose;
daemon = cfg->daemon; daemon = cfg->daemon;
will_save = cfg->will_save; will_save = cfg->will_save;
@ -18,53 +27,57 @@ Config::Config ( Config* cfg ) {
maxDate = cfg->maxDate; maxDate = cfg->maxDate;
} }
// !! handle file status // !! handle file status
void void
Config::Load () Config::Load()
{ {
if ( configDir == NULL ) if (configDir == NULL)
configDir = BString( "/boot/home/config/settings/Pogger/" ); configDir = BString("/boot/home/config/settings/Pogger/");
BString filename = BString(configDir); BString filename = BString(configDir);
filename.Append("settings"); filename.Append("settings");
BFile* file = new BFile( filename.String(), B_READ_ONLY ); BFile* file = new BFile(filename.String(), B_READ_ONLY);
status_t result = file->InitCheck(); status_t result = file->InitCheck();
BMessage storage; BMessage storage;
storage.Unflatten( file ); storage.Unflatten(file);
if ( outDir == NULL) if (outDir == NULL)
outDir = BString( storage.GetString("outDir", "/boot/home/feeds/") ); outDir = BString(storage.GetString("outDir", "/boot/home/feeds/"));
if ( cacheDir == NULL) if (cacheDir == NULL)
cacheDir = BString( storage.GetString("cacheDir", "/boot/home/config/cache/Pogger/") ); cacheDir = BString(storage.GetString("cacheDir",
"/boot/home/config/cache/Pogger/"));
delete file; delete file;
} }
// !! handle file status // !! handle file status
void void
Config::Save () Config::Save ()
{ {
if ( configDir == NULL ) if (configDir == NULL)
configDir = BString( "/boot/home/config/settings/Pogger/" ); configDir = BString("/boot/home/config/settings/Pogger/");
BPath* cfgPath = new BPath( configDir.String(), NULL, true ); BPath* cfgPath = new BPath(configDir.String(), NULL, true);
BEntry* cfgEntry = new BEntry( cfgPath->Path() ); BEntry* cfgEntry = new BEntry(cfgPath->Path());
BDirectory* cfgDir = new BDirectory; BDirectory* cfgDir = new BDirectory;
cfgDir->CreateDirectory(cfgPath->Path(), NULL); cfgDir->CreateDirectory(cfgPath->Path(), NULL);
if ( cfgEntry->Exists() == false ) if (cfgEntry->Exists() == false)
cfgDir->CreateDirectory( cfgPath->Path(), NULL ); cfgDir->CreateDirectory(cfgPath->Path(), NULL);
BMessage storage; BMessage storage;
BString filename = BString( configDir ).Append("/settings"); BString filename = BString(configDir).Append("/settings");
BFile* file = new BFile( filename.String(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE ); BFile* file = new BFile(filename.String(), B_WRITE_ONLY | B_CREATE_FILE
| B_ERASE_FILE);
status_t result = file->InitCheck(); status_t result = file->InitCheck();
storage.AddString( "outDir", outDir.String() ); storage.AddString("outDir", outDir.String());
storage.AddString( "cacheDir", cacheDir.String() ); storage.AddString("cacheDir", cacheDir.String());
storage.Flatten( file ); storage.Flatten(file);
} }

View File

@ -1,14 +1,23 @@
/*
* Copyright 2020, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#ifndef CONFIG_H #ifndef CONFIG_H
#define CONFIG_H #define CONFIG_H
#include <DateTime.h> #include <DateTime.h>
#include <String.h> #include <String.h>
#include <StorageKit.h> #include <StorageKit.h>
class Config { class Config {
public: public:
Config ( ); Config();
Config ( Config* ); Config(Config*);
void Load();
void Save();
bool verbose; bool verbose;
bool daemon; bool daemon;
@ -23,9 +32,8 @@ public:
bool will_save; bool will_save;
bool updateFeeds; bool updateFeeds;
void Load ( );
void Save ( );
}; };
#endif #endif

View File

@ -1,12 +1,20 @@
/*
* Copyright 2020, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#include "Entry.h"
#include <StorageKit.h>
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <tinyxml2.h>
#include <StorageKit.h>
#include "Config.h" #include "Config.h"
#include "Entry.h"
#include "Util.h" #include "Util.h"
Entry::Entry ( BString outputPath )
Entry::Entry(BString outputPath)
{ {
title = BString(""); title = BString("");
description = BString(""); description = BString("");
@ -16,90 +24,134 @@ Entry::Entry ( BString outputPath )
outputDir = outputPath; outputDir = outputPath;
} }
bool bool
Entry::Filetize ( bool onlyIfNew = false ) Entry::Filetize(bool onlyIfNew = false)
{ {
BDirectory* dir = new BDirectory( outputDir ); BDirectory* dir = new BDirectory(outputDir);
BFile* file = new BFile( title.String(), B_READ_WRITE ); BFile* file = new BFile(title.String(), B_READ_WRITE);
time_t tt_date = date.Time_t(); time_t tt_date = date.Time_t();
dir->CreateFile( title.String(), file ); dir->CreateFile(title.String(), file);
BString betype = BString("text/x-feed-entry"); BString betype = BString("text/x-feed-entry");
file->WriteAttr( "BEOS:TYPE", B_MIME_STRING_TYPE, 0, file->WriteAttr("BEOS:TYPE", B_MIME_STRING_TYPE, 0, betype.String(),
betype.String(), betype.CountChars() + 1 ); betype.CountChars() + 1);
file->WriteAttr( "FEED:name", B_STRING_TYPE, 0, file->WriteAttr("FEED:name", B_STRING_TYPE, 0,
title.String(), title.CountChars() ); title.String(), title.CountChars());
file->WriteAttr( "FEED:description", B_STRING_TYPE, 0, file->WriteAttr("FEED:description", B_STRING_TYPE, 0,
description.String(), description.CountChars() ); description.String(), description.CountChars());
file->WriteAttr( "FEED:source", B_STRING_TYPE, 0, file->WriteAttr("FEED:source", B_STRING_TYPE, 0,
feedTitle.String(), feedTitle.CountChars() ); feedTitle.String(), feedTitle.CountChars());
file->WriteAttr( "META:url", B_STRING_TYPE, 0, file->WriteAttr("META:url", B_STRING_TYPE, 0, postUrl.String(),
postUrl.String(), postUrl.CountChars() ); postUrl.CountChars());
if ( date != NULL ) {
file->WriteAttr( "FEED:when", B_TIME_TYPE, 0, if (date != NULL) {
&tt_date, sizeof(time_t) ); file->WriteAttr("FEED:when", B_TIME_TYPE, 0, &tt_date, sizeof(time_t));
} }
file->Write(content.String(), content.Length()); file->Write(content.String(), content.Length());
return false; return false;
} }
bool Entry::SetTitle ( const char* titleStr ) {
if ( titleStr != NULL ) title = BString( titleStr ); bool
else return false; Entry::SetTitle(const char* titleStr) {
return true; if (titleStr != NULL)
} title = BString(titleStr);
bool Entry::SetTitle ( tinyxml2::XMLElement* elem ) {
if ( elem != NULL ) return SetTitle( elem->GetText() );
return false;
}
bool Entry::SetDesc ( const char* descStr ) {
if ( descStr != NULL ) description = BString( descStr );
else return false;
return true;
}
bool Entry::SetDesc ( tinyxml2::XMLElement* elem ) {
if ( elem != NULL ) return SetDesc( elem->GetText() );
return false;
}
bool Entry::SetFeedTitle ( BString titleStr ) {
if ( titleStr != NULL ) feedTitle = titleStr;
else return false; else return false;
return true; return true;
} }
bool Entry::SetContent ( const char* contentStr ) {
if ( contentStr != NULL ) content = BString( contentStr ); bool
else return false; Entry::SetTitle(tinyxml2::XMLElement* elem) {
return true; if (elem != NULL)
} return SetTitle(elem->GetText());
bool Entry::SetContent ( tinyxml2::XMLElement* elem ) {
if ( elem != NULL ) return SetContent( elem->GetText() );
return false; return false;
} }
bool Entry::SetPostUrl ( const char* urlStr ) {
if ( urlStr != NULL ) postUrl = BString( urlStr ); bool
Entry::SetDesc(const char* descStr) {
if (descStr != NULL)
description = BString(descStr);
else return false; else return false;
return true; return true;
} }
bool Entry::SetPostUrl ( tinyxml2::XMLElement* elem ) {
if ( elem != NULL ) return SetPostUrl( elem->GetText() );
bool
Entry::SetDesc(tinyxml2::XMLElement* elem) {
if (elem != NULL)
return SetDesc(elem->GetText());
return false; return false;
} }
bool Entry::SetDate ( const char* dateStr ) {
if ( dateStr == NULL ) bool
Entry::SetFeedTitle(BString titleStr) {
if (titleStr != NULL)
feedTitle = titleStr;
else return false;
return true;
}
bool
Entry::SetContent(const char* contentStr)
{
if (contentStr != NULL)
content = BString(contentStr);
else return false;
return true;
}
bool
Entry::SetContent(tinyxml2::XMLElement* elem)
{
if (elem != NULL)
return SetContent(elem->GetText());
return false; return false;
BDateTime newDate = feedDateToBDate( dateStr ); }
if ( newDate == NULL )
bool
Entry::SetPostUrl(const char* urlStr) {
if (urlStr != NULL)
postUrl = BString(urlStr);
else return false;
return true;
}
bool
Entry::SetPostUrl(tinyxml2::XMLElement* elem) {
if (elem != NULL)
return SetPostUrl(elem->GetText());
return false;
}
bool
Entry::SetDate(const char* dateStr) {
if (dateStr == NULL)
return false;
BDateTime newDate = feedDateToBDate(dateStr);
if (newDate == NULL)
return false; return false;
date = newDate; date = newDate;
return true; return true;
} }
bool Entry::SetDate ( tinyxml2::XMLElement* elem ) {
if ( elem != NULL ) return SetDate( elem->GetText() );
bool
Entry::SetDate(tinyxml2::XMLElement* elem) {
if (elem != NULL)
return SetDate(elem->GetText());
return false; return false;
} }

View File

@ -1,14 +1,40 @@
/*
* Copyright 2020, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#ifndef ENTRY_H #ifndef ENTRY_H
#define ENTRY_H #define ENTRY_H
#include <DateTime.h> #include <DateTime.h>
#include <String.h>
#include <List.h> #include <List.h>
#include <String.h>
#include <Url.h> #include <Url.h>
#include <tinyxml2.h>
#include "Config.h" #include "Config.h"
class Entry { class Entry {
public: public:
Entry(BString);
bool Filetize(bool);
bool SetTitle(const char*);
bool SetTitle(tinyxml2::XMLElement*);
bool SetDesc(const char*);
bool SetDesc(tinyxml2::XMLElement*);
bool SetFeedTitle(BString);
bool SetContent(const char*);
bool SetContent(tinyxml2::XMLElement*);
bool SetPostUrl(const char*);
bool SetPostUrl(tinyxml2::XMLElement*);
bool SetDate(const char*);
bool SetDate(tinyxml2::XMLElement*);
BString title; BString title;
BString description; BString description;
BString feedTitle; BString feedTitle;
@ -16,22 +42,8 @@ public:
BString postUrl; BString postUrl;
BString content; BString content;
BString outputDir; BString outputDir;
Entry ( BString );
bool Filetize ( bool );
bool SetTitle ( const char* );
bool SetTitle ( tinyxml2::XMLElement* );
bool SetDesc ( const char* );
bool SetDesc ( tinyxml2::XMLElement* );
bool SetFeedTitle ( BString );
bool SetContent ( const char* );
bool SetContent ( tinyxml2::XMLElement* );
bool SetPostUrl ( const char* );
bool SetPostUrl ( tinyxml2::XMLElement* );
bool SetDate ( const char* );
bool SetDate ( tinyxml2::XMLElement* );
}; };
#endif #endif

View File

@ -1,23 +1,32 @@
/*
* Copyright 2020, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#include "Feed.h"
#include <tinyxml2.h> #include <tinyxml2.h>
#include "App.h" #include "App.h"
#include "Entry.h" #include "Entry.h"
#include "Config.h" #include "Config.h"
#include "Util.h" #include "Util.h"
#include "Feed.h"
Feed::Feed ( BString path )
Feed::Feed(BString path)
{ {
title = BString( "Untitled Feed" ); title = BString("Untitled Feed");
description = BString( "Nondescript, N/A." ); description = BString("Nondescript, N/A.");
homeUrl = BString(""); homeUrl = BString("");
xmlUrl = BString(""); xmlUrl = BString("");
updated = true; updated = true;
fetched = false; fetched = false;
inputPath = path; inputPath = path;
SetCachePath( path ); SetCachePath(path);
} }
Feed::Feed ( )
Feed::Feed()
{ {
title = BString(""); title = BString("");
description = BString(""); description = BString("");
@ -25,132 +34,133 @@ Feed::Feed ( )
xmlUrl = BString(""); xmlUrl = BString("");
} }
// ----------------------------------------------------------------------------
void void
Feed::Parse ( ) Feed::Parse()
{ {
BFile* feedFile = new BFile( GetCachePath().String(), B_READ_ONLY ); BFile* feedFile = new BFile(GetCachePath().String(), B_READ_ONLY);
time_t tt_lastDate = 0;
BDateTime attrLastDate = BDateTime(); BDateTime attrLastDate = BDateTime();
time_t tt_lastDate = 0;
feedFile->ReadAttr( "LastDate", B_TIME_TYPE, 0, &tt_lastDate, sizeof(time_t) ); feedFile->ReadAttr("LastDate", B_TIME_TYPE, 0, &tt_lastDate,
if ( tt_lastDate > 0 && ((App*)be_app)->cfg->updateFeeds == true ) { sizeof(time_t));
attrLastDate.SetTime_t( tt_lastDate );
if (tt_lastDate > 0 && ((App*)be_app)->cfg->updateFeeds == true) {
attrLastDate.SetTime_t(tt_lastDate);
minDate = attrLastDate; minDate = attrLastDate;
} }
} }
// -------------------------------------
// -------------------------------------
// Download a remote feed's XML to the cache path. // Download a remote feed's XML to the cache path.
BString BString
Feed::FetchRemoteFeed ( ) Feed::FetchRemoteFeed()
{ {
BUrl givenUrl = BUrl( inputPath ); BUrl givenUrl = BUrl(inputPath);
time_t tt_lastDate = 0; time_t tt_lastDate = 0;
BDateTime* lastDate = new BDateTime(); BDateTime* lastDate = new BDateTime();
BString* newHash = new BString(); BString* newHash = new BString();
char oldHash[41]; char oldHash[41];
BFile* cacheFile = new BFile( GetCachePath(), B_READ_WRITE | B_CREATE_FILE ); BFile* cacheFile = new BFile(GetCachePath(), B_READ_WRITE | B_CREATE_FILE);
cacheFile->ReadAttr( "LastHash", B_STRING_TYPE, 0, oldHash, 41 ); cacheFile->ReadAttr("LastHash", B_STRING_TYPE, 0, oldHash, 41);
if ( ((App*)be_app)->cfg->verbose ) if (((App*)be_app)->cfg->verbose)
printf( "Saving %s...\n", inputPath.String() ); printf("Saving %s...\n", inputPath.String());
webFetch( BUrl(inputPath), cacheFile, newHash ); webFetch(BUrl(inputPath), cacheFile, newHash);
cacheFile->WriteAttr( "LastHash", B_STRING_TYPE, 0, cacheFile->WriteAttr("LastHash", B_STRING_TYPE, 0,
newHash->String(), newHash->CountChars() ); newHash->String(), newHash->CountChars());
if ( *(newHash) == BString(oldHash) ) if (*(newHash) == BString(oldHash))
updated = false; updated = false;
fetched = true; fetched = true;
return GetCachePath(); return GetCachePath();
} }
// ----------------------------------------------------------------------------
// return whether or not the feed's given URI/path is remote. // return whether or not the feed's given URI/path is remote.
bool bool
Feed::IsRemote ( ) Feed::IsRemote ()
{ {
return isRemotePath( inputPath ); return isRemotePath(inputPath);
} }
// return whether or not the feed seems to have been updated // return whether or not the feed seems to have been updated
bool bool
Feed::IsUpdated ( ) Feed::IsUpdated ()
{ {
return updated; return updated;
} }
// return whether or not feed is RSS // return whether or not feed is RSS
bool bool
Feed::IsRss ( ) Feed::IsRss ()
{ {
EnsureCached(); EnsureCached();
tinyxml2::XMLDocument xml; tinyxml2::XMLDocument xml;
xml.LoadFile( GetCachePath().String() ); xml.LoadFile(GetCachePath().String());
if ( xml.FirstChildElement("rss") ) if (xml.FirstChildElement("rss"))
return true; return true;
return false; return false;
} }
// return whether or not feed is Atom // return whether or not feed is Atom
bool bool
Feed::IsAtom ( ) Feed::IsAtom ()
{ {
tinyxml2::XMLDocument xml; tinyxml2::XMLDocument xml;
xml.LoadFile( GetCachePath().String() ); xml.LoadFile(GetCachePath().String());
if ( xml.FirstChildElement("feed") ) if (xml.FirstChildElement("feed"))
return true; return true;
return false; return false;
} }
// ----------------------------------------------------------------------------
// ensure the feed XML is available at the cache path. // ensure the feed XML is available at the cache path.
// if necessary, download it. // if necessary, download it.
void void
Feed::EnsureCached ( ) Feed::EnsureCached ()
{ {
if ( IsRemote() && fetched == false ) if (IsRemote() && fetched == false)
FetchRemoteFeed(); FetchRemoteFeed();
} }
// Return the 'cachePath' (location of XML file locally) // Return the 'cachePath' (location of XML file locally)
BString BString
Feed::GetCachePath ( ) Feed::GetCachePath ()
{ {
if ( cachePath == NULL ) if (cachePath == NULL)
SetCachePath( inputPath ); SetCachePath(inputPath);
return cachePath; return cachePath;
} }
// Select a 'cachePath' (location of XML file locally) // Select a 'cachePath' (location of XML file locally)
// For remote files, a cache file is created in ~/config/cache/Pogger/ by default // For remote files, a cache file is created in ~/config/cache/Pogger/ by default
// For local files, the same local file is used. // For local files, the same local file is used.
BString BString
Feed::SetCachePath ( BString givenPath ) Feed::SetCachePath (BString givenPath)
{ {
BUrl givenUrl = BUrl( givenPath ); BUrl givenUrl = BUrl(givenPath);
BString protocol = givenUrl.Protocol().String(); BString protocol = givenUrl.Protocol().String();
if ( protocol == NULL && givenUrl.UrlString() != NULL ) { if (protocol == NULL && givenUrl.UrlString() != NULL) {
cachePath = givenPath; cachePath = givenPath;
return givenPath; return givenPath;
} }
BString splitName = givenUrl.Host( ); BString splitName = givenUrl.Host();
splitName.Append( givenUrl.Path() ); splitName.Append(givenUrl.Path());
splitName.ReplaceAll("/", "_"); splitName.ReplaceAll("/", "_");
BString filename = ((App*)be_app)->cfg->cacheDir; BString filename = ((App*)be_app)->cfg->cacheDir;
@ -160,85 +170,149 @@ Feed::SetCachePath ( BString givenPath )
return filename; return filename;
} }
// ----------------------------------------------------------------------------
// count the amount of siblings to an element of given type name // count the amount of siblings to an element of given type name
int int
Feed::xmlCountSiblings ( tinyxml2::XMLElement* xsibling, const char* sibling_name ) Feed::xmlCountSiblings (tinyxml2::XMLElement* xsibling, const char* sibling_name)
{ {
int count = 0; int count = 0;
while ( xsibling ) { while (xsibling) {
count++; count++;
xsibling = xsibling->NextSiblingElement(sibling_name); xsibling = xsibling->NextSiblingElement(sibling_name);
} }
return count; return count;
} }
// ----------------------------------------------------------------------------
// add the given entry to the feed, if appropriate // add the given entry to the feed, if appropriate
bool bool
Feed::AddEntry ( Entry* newEntry ) Feed::AddEntry (Entry* newEntry)
{ {
Config* cfg = ((App*)be_app)->cfg; Config* cfg = ((App*)be_app)->cfg;
if ( !withinDateRange( cfg->minDate, newEntry->date, cfg->maxDate ) || if (!withinDateRange(cfg->minDate, newEntry->date, cfg->maxDate) ||
!withinDateRange( minDate, newEntry->date, maxDate ) ) !withinDateRange(minDate, newEntry->date, maxDate))
return false; return false;
if ( cfg->verbose == true ) if (cfg->verbose == true)
printf( "\t%s\n", newEntry->title.String() ); printf("\t%s\n", newEntry->title.String());
entries.AddItem( newEntry ); entries.AddItem(newEntry);
return true; return true;
} }
BList Feed::GetEntries ( ) { return entries; }
bool Feed::SetTitle ( const char* titleStr ) {
if ( titleStr != NULL ) title = BString( titleStr );
else return false;
return true;
}
bool Feed::SetTitle ( tinyxml2::XMLElement* elem ) {
if ( elem != NULL ) return SetTitle( elem->GetText() );
else return false;
}
BString Feed::GetTitle ( ) { return title; }
bool Feed::SetDesc ( const char* descStr ) { BList
if ( descStr != NULL ) description = BString( descStr ); Feed::GetEntries()
{
return entries;
}
bool
Feed::SetTitle(const char* titleStr)
{
if (titleStr != NULL)
title = BString(titleStr);
else return false; else return false;
return true; return true;
} }
bool Feed::SetDesc ( tinyxml2::XMLElement* elem ) {
if ( elem != NULL ) return SetDesc( elem->GetText() );
bool
Feed::SetTitle(tinyxml2::XMLElement* elem)
{
if (elem != NULL)
return SetTitle(elem->GetText());
else return false; else return false;
} }
BString Feed::GetDesc ( ) { return description; }
BString
Feed::GetTitle()
{
return title;
}
bool
Feed::SetDesc(const char* descStr)
{
if (descStr != NULL)
description = BString(descStr);
else return false;
return true;
}
bool
Feed::SetDesc(tinyxml2::XMLElement* elem)
{
if (elem != NULL)
return SetDesc(elem->GetText());
else return false;
}
BString
Feed::GetDesc()
{
return description;
}
// set a feed's «home URL» // set a feed's «home URL»
bool Feed::SetHomeUrl ( const char* homepageStr ) { bool
if ( homepageStr != NULL ) homeUrl = BString( homepageStr ); Feed::SetHomeUrl(const char* homepageStr)
{
if (homepageStr != NULL)
homeUrl = BString(homepageStr);
else return false; else return false;
return true; return true;
} }
bool Feed::SetHomeUrl ( tinyxml2::XMLElement* elem ) {
if ( elem != NULL ) return SetHomeUrl( elem->GetText() );
bool
Feed::SetHomeUrl(tinyxml2::XMLElement* elem)
{
if (elem != NULL)
return SetHomeUrl(elem->GetText());
else return false; else return false;
} }
BString Feed::GetHomeUrl ( ) { return homeUrl; }
BString
Feed::GetHomeUrl()
{
return homeUrl;
}
// set the update time for a feed // set the update time for a feed
bool Feed::SetDate ( const char* dateCStr ) { bool
if ( dateCStr == NULL ) Feed::SetDate(const char* dateCStr)
{
if (dateCStr == NULL)
return false; return false;
BDateTime newDate = feedDateToBDate( dateCStr ); BDateTime newDate = feedDateToBDate(dateCStr);
if ( newDate == NULL ) if (newDate == NULL)
return false; return false;
date = newDate; date = newDate;
return true; return true;
} }
bool Feed::SetDate ( tinyxml2::XMLElement* elem ) {
if ( elem != NULL ) return SetDate( elem->GetText() );
bool
Feed::SetDate(tinyxml2::XMLElement* elem)
{
if (elem != NULL)
return SetDate(elem->GetText());
else return false; else return false;
} }
BDateTime Feed::GetDate ( ) { return date; }
BDateTime
Feed::GetDate()
{
return date;
}

View File

@ -1,47 +1,56 @@
/*
* Copyright 2020, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#ifndef FEED_H #ifndef FEED_H
#define FEED_H #define FEED_H
#include <tinyxml2.h> #include <tinyxml2.h>
#include <DateTime.h>
#include <String.h>
#include <List.h>
#include <Url.h>
#include "Entry.h" #include "Entry.h"
class BDateTime;
class BString;
class BList;
class BUrl;
class Feed { class Feed {
public: public:
Feed ( BString ); Feed(BString);
Feed ( ); Feed();
virtual void Parse ( ); virtual void Parse();
bool IsRemote ( ); bool IsRemote();
bool IsUpdated ( ); bool IsUpdated();
bool IsRss ( ); bool IsRss();
bool IsAtom ( ); bool IsAtom();
bool AddEntry ( Entry* ); bool AddEntry(Entry*);
BList GetEntries ( ); BList GetEntries();
bool SetTitle ( const char* ); bool SetTitle(const char*);
bool SetTitle ( tinyxml2::XMLElement* ); bool SetTitle(tinyxml2::XMLElement*);
BString GetTitle ( ); BString GetTitle();
bool SetDesc ( const char* ); bool SetDesc(const char*);
bool SetDesc ( tinyxml2::XMLElement* ); bool SetDesc(tinyxml2::XMLElement*);
BString GetDesc ( ); BString GetDesc();
bool SetHomeUrl ( const char* ); bool SetHomeUrl(const char*);
bool SetHomeUrl ( tinyxml2::XMLElement* ); bool SetHomeUrl(tinyxml2::XMLElement*);
BString GetHomeUrl ( ); BString GetHomeUrl();
bool SetDate ( const char* ); bool SetDate(const char*);
bool SetDate ( tinyxml2::XMLElement* ); bool SetDate(tinyxml2::XMLElement*);
BDateTime GetDate ( ); BDateTime GetDate();
BString SetCachePath ( BString ); BString SetCachePath(BString);
BString GetCachePath ( ); BString GetCachePath();
protected: protected:
void EnsureCached ( ); void EnsureCached();
BString FetchRemoteFeed ( ); BString FetchRemoteFeed();
int xmlCountSiblings ( tinyxml2::XMLElement*, const char* ); int xmlCountSiblings(tinyxml2::XMLElement*, const char*);
BString title; BString title;
BString description; BString description;
@ -57,7 +66,8 @@ protected:
BList entries; BList entries;
bool fetched; bool fetched;
bool updated; bool updated;
}; };
#endif #endif

View File

@ -1,25 +1,35 @@
#include <StorageKit.h> /*
#include <String.h> * Copyright 2020, Jaidyn Levesque <jadedctrl@teknik.io>
#include <getopt.h> * All rights reserved. Distributed under the terms of the MIT license.
#include "AtomFeed.h" */
#include "RssFeed.h"
#include "Feed.h"
#include "Entry.h"
#include "Mimetypes.h"
#include "Config.h"
#include "Util.h"
#include "App.h"
#include "Invocation.h" #include "Invocation.h"
#include <StorageKit.h>
#include <String.h>
#include <getopt.h>
#include "App.h"
#include "AtomFeed.h"
#include "Config.h"
#include "Entry.h"
#include "Feed.h"
#include "Mimetypes.h"
#include "RssFeed.h"
#include "Util.h"
int int
usage ( ) usage()
{ {
fprintf(stderr, "%s", usageMsg.String()); fprintf(stderr, "%s", usageMsg.String());
return 2; return 2;
} }
int int
invocation ( int argc, char** argv ) invocation(int argc, char** argv)
{ {
Config* cfg = ((App*)be_app)->cfg; Config* cfg = ((App*)be_app)->cfg;
BDateTime maxDate; BDateTime maxDate;
@ -44,21 +54,21 @@ invocation ( int argc, char** argv )
switch (c) { switch (c) {
case -1: case -1:
freeargInvocation( argc, argv, optind ); freeargInvocation(argc, argv, optind);
return 0; return 0;
case 'h': case 'h':
return usage(); return usage();
case 'c': case 'c':
cfg->configDir = BString( optarg ); cfg->configDir = BString(optarg);
break; break;
case 'C': case 'C':
cfg->cacheDir = BString( optarg ); cfg->cacheDir = BString(optarg);
break; break;
case 's': case 's':
cfg->will_save = true; cfg->will_save = true;
case 't': case 't':
minDate = dateRfc3339ToBDate( optarg ); minDate = dateRfc3339ToBDate(optarg);
if ( minDate != NULL ) if (minDate != NULL)
cfg->minDate = minDate; cfg->minDate = minDate;
else { else {
fprintf(stderr, "Invalid date format for `-%c'.\n", optopt); fprintf(stderr, "Invalid date format for `-%c'.\n", optopt);
@ -66,8 +76,8 @@ invocation ( int argc, char** argv )
} }
break; break;
case 'T': case 'T':
maxDate = dateRfc3339ToBDate( optarg ); maxDate = dateRfc3339ToBDate(optarg);
if ( maxDate != NULL ) if (maxDate != NULL)
cfg->maxDate = maxDate; cfg->maxDate = maxDate;
else { else {
fprintf(stderr, "Invalid date format for `-%c'.\n", optopt); fprintf(stderr, "Invalid date format for `-%c'.\n", optopt);
@ -75,7 +85,7 @@ invocation ( int argc, char** argv )
} }
break; break;
case 'O': case 'O':
cfg->outDir = BString( optarg ); cfg->outDir = BString(optarg);
break; break;
case 'u': case 'u':
cfg->updateFeeds = true; cfg->updateFeeds = true;
@ -87,62 +97,62 @@ invocation ( int argc, char** argv )
cfg->daemon = false; cfg->daemon = false;
break; break;
case '?': case '?':
if ( optopt == 'O' || optopt == 'm' ) if (optopt == 'O' || optopt == 'm')
fprintf( stderr, "Option `-%c` requires an argument.\n", fprintf(stderr, "Option `-%c` requires an argument.\n",
optopt ); optopt);
else else
fprintf( stderr, "Unknown option `-%c`.\n", optopt ); fprintf(stderr, "Unknown option `-%c`.\n", optopt);
return 2; return 2;
} }
} }
} }
// -------------------------------------
void void
freeargInvocation ( int argc, char** argv, int optind ) freeargInvocation(int argc, char** argv, int optind)
{ {
Config* cfg = ((App*)be_app)->cfg; Config* cfg = ((App*)be_app)->cfg;
if ( optind < argc ) { if (optind < argc) {
int freeargc = argc - optind; int freeargc = argc - optind;
cfg->targetFeeds = BList( freeargc ); cfg->targetFeeds = BList(freeargc);
for ( int i = 0; i < freeargc; i++ ) { for (int i = 0; i < freeargc; i++) {
BString* newFeed = new BString( argv[optind + i] ); BString* newFeed = new BString(argv[optind + i]);
cfg->targetFeeds.AddItem( newFeed ); cfg->targetFeeds.AddItem(newFeed);
} }
} }
} }
// ----------------------------------------------------------------------------
bool bool
processEntry ( void* entry ) processEntry(void* entry)
{ {
Entry* entryPtr = (Entry*)entry; Entry* entryPtr = (Entry*)entry;
entryPtr->Filetize( false ); entryPtr->Filetize(false);
return false; return false;
} }
bool bool
processFeed ( void* feedArg ) processFeed(void* feedArg)
{ {
BString* feedStr = (BString*)feedArg; BString* feedStr = (BString*)feedArg;
Feed* testFeed = new Feed( *(feedStr) ); Feed* testFeed = new Feed(*(feedStr));
BList entries; BList entries;
if ( testFeed->IsUpdated() == false && ((App*)be_app)->cfg->updateFeeds == true ) if (testFeed->IsUpdated() == false
&& ((App*)be_app)->cfg->updateFeeds == true)
return false; return false;
if ( testFeed->IsAtom() ) { if (testFeed->IsAtom()) {
AtomFeed* feed = (AtomFeed*)malloc( sizeof(AtomFeed) ); AtomFeed* feed = (AtomFeed*)malloc(sizeof(AtomFeed));
feed = new AtomFeed( testFeed ); feed = new AtomFeed(testFeed);
feed->Parse(); feed->Parse();
entries = feed->GetEntries(); entries = feed->GetEntries();
} }
if ( testFeed->IsRss() ) { if (testFeed->IsRss()) {
RssFeed* feed = (RssFeed*)malloc( sizeof(RssFeed) ); RssFeed* feed = (RssFeed*)malloc(sizeof(RssFeed));
feed = new RssFeed( testFeed ); feed = new RssFeed(testFeed);
feed->Parse(); feed->Parse();
entries = feed->GetEntries(); entries = feed->GetEntries();
} }
@ -150,3 +160,5 @@ processFeed ( void* feedArg )
entries.DoForEach(&processEntry); entries.DoForEach(&processEntry);
return false; return false;
} }

View File

@ -1,7 +1,10 @@
/*
* Copyright 2020, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#ifndef INVOCATION_H #ifndef INVOCATION_H
#define INVOCATION_H #define INVOCATION_H
#include <StorageKit.h>
int usage ( ); int usage ( );
int invocation ( int, char** ); int invocation ( int, char** );
@ -9,6 +12,6 @@ void freeargInvocation ( int, char**, int );
bool processItem ( void* ); bool processItem ( void* );
bool processFeed ( void* ); bool processFeed ( void* );
// ----------------------------------------------------------------------------
#endif #endif

View File

@ -1,47 +1,54 @@
// borrowed significantly (addAttribute) from mailserver. thanks! <3 /*
#include <iostream> * Copyright 2020, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#include "Mimetypes.h"
#include <Application.h> #include <Application.h>
#include <DateTime.h> #include <DateTime.h>
#include <Message.h> #include <Message.h>
#include <MimeType.h> #include <MimeType.h>
#include "Mimetypes.h"
// install the Feed Entry mimetype, if need be // install the Feed Entry mimetype, if need be
bool bool
feedMimeType ( ) feedMimeType()
{ {
BMessage info; BMessage info;
BMimeType mime( "text/x-feed-entry" ); BMimeType mime("text/x-feed-entry");
if ( mime.IsInstalled() ) return true; if (mime.IsInstalled())
return true;
std::cout << "NOT INSTALLED"; mime.GetAttrInfo(&info);
mime.GetAttrInfo( &info );
mime.SetShortDescription( "Feed Entry" ); mime.SetShortDescription("Feed Entry");
mime.SetLongDescription( "Atom/RSS Feed Entry" ); mime.SetLongDescription("Atom/RSS Feed Entry");
addAttribute( info, "FEED:name", "Name" ); addAttribute(info, "FEED:name", "Name");
addAttribute( info, "FEED:description", "Description" ); addAttribute(info, "FEED:description", "Description");
addAttribute( info, "META:url", "URL" ); addAttribute(info, "META:url", "URL");
addAttribute( info, "FEED:source", "Source" ); addAttribute(info, "FEED:source", "Source");
addAttribute( info, "FEED:when", "When", B_TIME_TYPE, 150 ); addAttribute(info, "FEED:when", "When", B_TIME_TYPE, 150);
return mime.SetAttrInfo( &info ); return mime.SetAttrInfo(&info);
} }
// -------------------------------------
// add the given attribute to a BMessage for use as attr info // add the given attribute to a BMessage for use as attr info
// borrowed from mailserver (thanks!)
static void static void
addAttribute addAttribute(BMessage& msg, const char* name, const char* publicName,
( BMessage& msg, const char* name, const char* publicName, int32 type, int32 width ) int32 type, int32 width)
{ {
msg.AddString( "attr:name", name ); msg.AddString("attr:name", name);
msg.AddString( "attr:public_name", publicName ); msg.AddString("attr:public_name", publicName);
msg.AddInt32( "attr:type", type ); msg.AddInt32("attr:type", type);
msg.AddInt32( "attr:width", width ); msg.AddInt32("attr:width", width);
msg.AddInt32( "attr:alignment", B_ALIGN_LEFT ); msg.AddInt32("attr:alignment", B_ALIGN_LEFT);
msg.AddBool( "attr:extra", false ); msg.AddBool("attr:extra", false);
msg.AddBool( "attr:viewable", true ); msg.AddBool("attr:viewable", true);
msg.AddBool( "attr:editable", true ); msg.AddBool("attr:editable", true);
} }

View File

@ -1,13 +1,22 @@
/*
* Copyright 2020, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#ifndef MIME_H #ifndef MIME_H
#define MIME_H #define MIME_H
#include <Message.h> #include <SupportDefs.h>
#include <String.h> #include <TypeConstants.h>
bool feedMimeType ( );
static void addAttribute class BMessage;
( BMessage&, const char*, const char*, int32 type = B_STRING_TYPE, int32 width = 200);
bool feedMimeType();
static void addAttribute(BMessage&, const char*, const char*,
int32 type = B_STRING_TYPE, int32 width = 200);
#endif #endif

View File

@ -1,63 +1,78 @@
#include <iostream> /*
#include <sstream> * Copyright 2020, Jaidyn Levesque <jadedctrl@teknik.io>
#include <UrlProtocolListener.h> * All rights reserved. Distributed under the terms of the MIT license.
#include <Url.h> */
#include <boost/uuid/detail/sha1.hpp>
#include "ProtocolListener.h" #include "ProtocolListener.h"
ProtocolListener::ProtocolListener ( bool traceLogging ) #include <Url.h>
#include <iostream>
#include <sstream>
ProtocolListener::ProtocolListener(bool traceLogging)
: :
fDownloadIO(NULL), fDownloadIO(NULL),
fTraceLogging(traceLogging) fTraceLogging(traceLogging)
{ } {}
ProtocolListener::~ProtocolListener()
{}
ProtocolListener::~ProtocolListener ( )
{ }
void void
ProtocolListener::DataReceived ( BUrlRequest* caller, const char* data, off_t position, ssize_t size ) ProtocolListener::DataReceived(BUrlRequest* caller, const char* data,
off_t position, ssize_t size)
{ {
if ( fDownloadIO != NULL ) if (fDownloadIO != NULL)
fDownloadIO->Write( data, size ); fDownloadIO->Write(data, size);
if ( fSha1 != NULL ) if (fSha1 != NULL)
fSha1->process_bytes( data, size ); fSha1->process_bytes(data, size);
} }
void void
ProtocolListener::SetDownloadIO ( BDataIO* downloadIO ) ProtocolListener::SetDownloadIO(BDataIO* downloadIO)
{ {
fDownloadIO = downloadIO; fDownloadIO = downloadIO;
} }
BDataIO* BDataIO*
ProtocolListener::GetDownloadIO ( ) ProtocolListener::GetDownloadIO()
{ {
return fDownloadIO; return fDownloadIO;
} }
void void
ProtocolListener::SetSha1 ( boost::uuids::detail::sha1* sha1 ) ProtocolListener::SetSha1(boost::uuids::detail::sha1* sha1)
{ {
fSha1 = sha1; fSha1 = sha1;
} }
boost::uuids::detail::sha1* boost::uuids::detail::sha1*
ProtocolListener::GetSha1 ( ) ProtocolListener::GetSha1()
{ {
return fSha1; return fSha1;
} }
BString BString
ProtocolListener::GetHash ( ) ProtocolListener::GetHash()
{ {
unsigned int hashInt[5]; unsigned int hashInt[5];
fSha1->get_digest( hashInt ); fSha1->get_digest(hashInt);
std::ostringstream hashStr; std::ostringstream hashStr;
for(std::size_t i=0; i<sizeof(hashInt)/sizeof(hashInt[0]); ++i) { for(std::size_t i=0; i<sizeof(hashInt)/sizeof(hashInt[0]); ++i) {
hashStr << std::hex <<hashInt[i]; hashStr << std::hex <<hashInt[i];
} }
return BString( hashStr.str().c_str() ); return BString(hashStr.str().c_str());
} }

View File

@ -1,24 +1,29 @@
/*
* Copyright 2020, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#ifndef PROTOCOL_LISTENER_H #ifndef PROTOCOL_LISTENER_H
#define PROTOCOL_LISTENER_H #define PROTOCOL_LISTENER_H
#include <UrlProtocolListener.h>
#include <Url.h>
#include <boost/uuid/detail/sha1.hpp> #include <boost/uuid/detail/sha1.hpp>
#include <UrlProtocolListener.h>
class ProtocolListener : public BUrlProtocolListener class ProtocolListener : public BUrlProtocolListener
{ {
public: public:
ProtocolListener ( bool ); ProtocolListener(bool);
virtual ~ProtocolListener(); virtual ~ProtocolListener();
virtual void DataReceived(BUrlRequest*, const char*, off_t, ssize_t); virtual void DataReceived(BUrlRequest*, const char*, off_t, ssize_t);
void SetDownloadIO ( BDataIO* ); void SetDownloadIO(BDataIO*);
BDataIO* GetDownloadIO ( ); BDataIO* GetDownloadIO();
void SetSha1 ( boost::uuids::detail::sha1* ); void SetSha1(boost::uuids::detail::sha1*);
boost::uuids::detail::sha1* GetSha1 ( ); boost::uuids::detail::sha1* GetSha1();
BString GetHash ( ); BString GetHash();
private: private:
BDataIO* fDownloadIO; BDataIO* fDownloadIO;
@ -26,4 +31,6 @@ private:
bool fTraceLogging; bool fTraceLogging;
}; };
#endif #endif

View File

@ -1,11 +1,17 @@
#include <tinyxml2.h> /*
#include "Entry.h" * Copyright 2020, Jaidyn Levesque <jadedctrl@teknik.io>
#include "App.h" * All rights reserved. Distributed under the terms of the MIT license.
#include "Config.h" */
#include "Util.h"
#include "RssFeed.h" #include "RssFeed.h"
RssFeed::RssFeed ( ) #include "App.h"
#include "Config.h"
#include "Entry.h"
#include "Util.h"
RssFeed::RssFeed()
{ {
title = BString("Untitled Feed"); title = BString("Untitled Feed");
description = BString(""); description = BString("");
@ -14,78 +20,81 @@ RssFeed::RssFeed ( )
outputDir = ((App*)be_app)->cfg->outDir; outputDir = ((App*)be_app)->cfg->outDir;
} }
RssFeed::RssFeed ( Feed* feed ) : RssFeed::RssFeed()
{ SetCachePath( feed->GetCachePath() ); }
// ---------------------------------------------------------------------------- RssFeed::RssFeed(Feed* feed) : RssFeed::RssFeed()
{ SetCachePath(feed->GetCachePath()); }
void void
RssFeed::Parse ( ) RssFeed::Parse()
{ {
tinyxml2::XMLDocument xml; tinyxml2::XMLDocument xml;
entries = BList(); entries = BList();
Feed::Parse(); Feed::Parse();
xml.LoadFile( GetCachePath().String() ); xml.LoadFile(GetCachePath().String());
tinyxml2::XMLElement* xchan = xml.FirstChildElement("rss")->FirstChildElement("channel"); tinyxml2::XMLElement* xchan = xml.FirstChildElement("rss")->FirstChildElement("channel");
RootParse( xchan ); RootParse(xchan);
ParseEntries( xchan ); ParseEntries(xchan);
time_t tt_lastDate = lastDate.Time_t(); time_t tt_lastDate = lastDate.Time_t();
BFile* feedFile = new BFile( GetCachePath().String(), B_READ_ONLY ); BFile* feedFile = new BFile(GetCachePath().String(), B_READ_ONLY);
feedFile->WriteAttr( "LastDate", B_TIME_TYPE, 0, &tt_lastDate, sizeof(time_t) ); feedFile->WriteAttr("LastDate", B_TIME_TYPE, 0, &tt_lastDate, sizeof(time_t));
} }
// -------------------------------------
void void
RssFeed::RootParse ( tinyxml2::XMLElement* xchan ) RssFeed::RootParse(tinyxml2::XMLElement* xchan)
{ {
SetTitle ( xchan->FirstChildElement("title") ); SetTitle(xchan->FirstChildElement("title"));
SetDesc ( xchan->FirstChildElement("description") ); SetDesc(xchan->FirstChildElement("description"));
SetHomeUrl ( xchan->FirstChildElement("link") ); SetHomeUrl(xchan->FirstChildElement("link"));
SetDate ( xchan->FirstChildElement("lastBuildDate") ); SetDate(xchan->FirstChildElement("lastBuildDate"));
if ( ((App*)be_app)->cfg->verbose ) if (((App*)be_app)->cfg->verbose)
printf("Channel '%s' at '%s':\n", title.String(), homeUrl.String()); printf("Channel '%s' at '%s':\n", title.String(), homeUrl.String());
} }
void void
RssFeed::EntryParse ( tinyxml2::XMLElement* xitem ) RssFeed::EntryParse(tinyxml2::XMLElement* xitem)
{ {
Entry* newEntry = (Entry*)malloc( sizeof(Entry) ); Entry* newEntry = (Entry*)malloc(sizeof(Entry));
newEntry = new Entry( outputDir ); newEntry = new Entry(outputDir);
newEntry->SetTitle ( xitem->FirstChildElement("title") ); newEntry->SetTitle(xitem->FirstChildElement("title"));
newEntry->SetDesc ( xitem->FirstChildElement("description") ); newEntry->SetDesc(xitem->FirstChildElement("description"));
newEntry->SetDate ( xitem->FirstChildElement("pubDate") ); newEntry->SetDate(xitem->FirstChildElement("pubDate"));
newEntry->SetPostUrl ( xitem->FirstChildElement("link") ); newEntry->SetPostUrl(xitem->FirstChildElement("link"));
newEntry->SetContent ( xitem->FirstChildElement("content:encoded") ); newEntry->SetContent(xitem->FirstChildElement("content:encoded"));
newEntry->SetFeedTitle( title ); newEntry->SetFeedTitle(title);
if ( lastDate == NULL || lastDate < newEntry->date ) if (lastDate == NULL || lastDate < newEntry->date)
lastDate = newEntry->date; lastDate = newEntry->date;
AddEntry( newEntry ); AddEntry(newEntry);
} }
void void
RssFeed::ParseEntries ( tinyxml2::XMLElement* xchan ) RssFeed::ParseEntries(tinyxml2::XMLElement* xchan)
{ {
tinyxml2::XMLElement* xitem; tinyxml2::XMLElement* xitem;
xitem = xchan->FirstChildElement("item"); xitem = xchan->FirstChildElement("item");
int entryCount = xmlCountSiblings( xitem, "item" ); int entryCount = xmlCountSiblings(xitem, "item");
entries = BList(entryCount); entries = BList(entryCount);
if ( ((App*)be_app)->cfg->verbose ) if (((App*)be_app)->cfg->verbose)
printf("\t-%i entries-\n", entryCount); printf("\t-%i entries-\n", entryCount);
while ( xitem ) { while (xitem) {
EntryParse( xitem ); EntryParse(xitem);
xitem = xitem->NextSiblingElement("item"); xitem = xitem->NextSiblingElement("item");
} }
} }

View File

@ -1,22 +1,26 @@
/*
* Copyright 2020, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#ifndef RSS_FEED_H #ifndef RSS_FEED_H
#define RSS_FEED_H #define RSS_FEED_H
#include <tinyxml2.h> #include <tinyxml2.h>
#include <DateTime.h>
#include <String.h>
#include <List.h>
#include <Url.h>
#include "Feed.h" #include "Feed.h"
class RssFeed: public Feed { class RssFeed: public Feed {
public: public:
RssFeed ( ); RssFeed();
RssFeed ( Feed* ); RssFeed(Feed*);
void Parse ( ); void Parse();
void RootParse ( tinyxml2::XMLElement* ); void RootParse(tinyxml2::XMLElement*);
void EntryParse ( tinyxml2::XMLElement* ); void EntryParse(tinyxml2::XMLElement*);
void ParseEntries ( tinyxml2::XMLElement* ); void ParseEntries(tinyxml2::XMLElement*);
}; };
#endif #endif

View File

@ -1,117 +1,125 @@
#include <iostream> /*
#include <sstream> * Copyright 2020, Jaidyn Levesque <jadedctrl@teknik.io>
#include <locale> * All rights reserved. Distributed under the terms of the MIT license.
#include <iomanip> */
#include <DateTime.h>
#include <UrlProtocolRoster.h>
#include <Url.h>
#include <UrlRequest.h>
#include <boost/uuid/detail/sha1.hpp>
#include "ProtocolListener.h"
#include "Util.h" #include "Util.h"
// ---------------------------------------------------------------------------- #include <Url.h>
#include <UrlProtocolRoster.h>
#include <UrlRequest.h>
#include <boost/uuid/detail/sha1.hpp>
#include <iostream>
#include <iomanip>
#include "ProtocolListener.h"
BDateTime BDateTime
feedDateToBDate ( const char* dateCStr ) feedDateToBDate(const char* dateCStr)
{ {
BDateTime date = dateRfc822ToBDate( dateCStr ); BDateTime date = dateRfc822ToBDate(dateCStr);
if ( date == NULL ) date = dateRfc3339ToBDate( dateCStr ); if (date == NULL)
date = dateRfc3339ToBDate(dateCStr);
return date; return date;
} }
BDateTime
dateRfc3339ToBDate ( const char* dateCStr )
{
return stringDateToBDate( dateCStr, "%Y-%m-%dT%H:%M:%S" );
}
BDateTime BDateTime
dateRfc822ToBDate ( const char* dateCStr ) dateRfc3339ToBDate(const char* dateCStr)
{ {
return stringDateToBDate( dateCStr, "%a, %d %b %Y %H:%M:%S" ); return stringDateToBDate(dateCStr, "%Y-%m-%dT%H:%M:%S");
} }
BDateTime BDateTime
stringDateToBDate ( const char* dateCStr, const char* templateCStr ) dateRfc822ToBDate(const char* dateCStr)
{ {
std::istringstream dateStream( dateCStr ); return stringDateToBDate(dateCStr, "%a, %d %b %Y %H:%M:%S");
}
BDateTime
stringDateToBDate(const char* dateCStr, const char* templateCStr)
{
std::istringstream dateStream(dateCStr);
std::tm time = {}; std::tm time = {};
if ( dateStream >> std::get_time( &time, templateCStr ) ) { if (dateStream >> std::get_time(&time, templateCStr)) {
BTime newTime = BTime( time.tm_hour, time.tm_min, time.tm_sec, 0 ); BTime newTime = BTime(time.tm_hour, time.tm_min, time.tm_sec, 0);
BDate newDate = BDate( time.tm_year + 1900, time.tm_mon + 1, time.tm_mday ); BDate newDate = BDate(time.tm_year + 1900, time.tm_mon + 1,
return BDateTime( newDate, newTime ); time.tm_mday);
return BDateTime(newDate, newTime);
} }
return NULL; return NULL;
} }
// ----------------------------------------------------------------------------
BString BString
dateTo3339String ( BDateTime dt ) dateTo3339String(BDateTime dt)
{ {
char buffer[18]; char buffer[18];
sprintf( buffer, "%i-%02i-%02iT%02i:%02i:%02i", sprintf(buffer, "%i-%02i-%02iT%02i:%02i:%02i",
dt.Date().Year(), dt.Date().Month(), dt.Date().Day(), dt.Date().Year(), dt.Date().Month(), dt.Date().Day(),
dt.Time().Hour(), dt.Time().Minute(), dt.Time().Second() ); dt.Time().Hour(), dt.Time().Minute(), dt.Time().Second());
return BString( buffer ); return BString(buffer);
} }
// ----------------------------------------------------------------------------
bool bool
withinDateRange ( BDateTime minDate, BDateTime nowDate, BDateTime maxDate ) withinDateRange(BDateTime minDate, BDateTime nowDate, BDateTime maxDate)
{ {
if ( minDate != NULL && nowDate != NULL && maxDate != NULL ) if (minDate != NULL && nowDate != NULL && maxDate != NULL)
return ( minDate < nowDate && nowDate < maxDate ); return (minDate < nowDate && nowDate < maxDate);
if ( minDate != NULL && nowDate != NULL ) if (minDate != NULL && nowDate != NULL)
return ( minDate < nowDate ); return (minDate < nowDate);
if ( maxDate != NULL && nowDate != NULL ) if (maxDate != NULL && nowDate != NULL)
return ( nowDate < maxDate ); return (nowDate < maxDate);
return true; return true;
} }
// ----------------------------------------------------------------------------
// return whether or not the given path is remote // return whether or not the given path is remote
bool bool
isRemotePath ( BString path ) { isRemotePath(BString path) {
BUrl givenUrl = BUrl( path ); BUrl givenUrl = BUrl(path);
BString protocol = givenUrl.Protocol().String(); BString protocol = givenUrl.Protocol().String();
if ( protocol == NULL || protocol == BString("file") || givenUrl.UrlString() == NULL ) if (protocol == NULL || protocol == BString("file")
|| givenUrl.UrlString() == NULL)
return false; return false;
return true; return true;
} }
// ----------------------------------------------------------------------------
int32 int32
webFetch ( BUrl url, BDataIO* reply ) webFetch(BUrl url, BDataIO* reply)
{ {
BString* ignored = new BString(); BString* ignored = new BString();
return webFetch( url, reply, ignored ); return webFetch(url, reply, ignored);
} }
int32 int32
webFetch ( BUrl url, BDataIO* reply, BString* hash ) webFetch(BUrl url, BDataIO* reply, BString* hash)
{ {
ProtocolListener listener(true); ProtocolListener listener(true);
boost::uuids::detail::sha1 sha1; boost::uuids::detail::sha1 sha1;
BUrlRequest* request = BUrlProtocolRoster::MakeRequest( url, &listener ); BUrlRequest* request = BUrlProtocolRoster::MakeRequest(url, &listener);
listener.SetDownloadIO( reply ); listener.SetDownloadIO(reply);
listener.SetSha1( &sha1 ); listener.SetSha1(&sha1);
thread_id thread = request->Run(); thread_id thread = request->Run();
wait_for_thread( thread, NULL ); wait_for_thread(thread, NULL);
*(hash) = listener.GetHash(); *(hash) = listener.GetHash();
return request->Status(); return request->Status();
return 200; return 200;
} }

View File

@ -1,22 +1,31 @@
/*
* Copyright 2020, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#ifndef UTIL_H #ifndef UTIL_H
#define UTIL_H #define UTIL_H
#include <DateTime.h> #include <DateTime.h>
#include <Url.h>
#include "ProtocolListener.h" #include "ProtocolListener.h"
BDateTime feedDateToBDate ( const char* ); class BUrl;
BDateTime dateRfc3339ToBDate ( const char* );
BDateTime dateRfc822ToBDate ( const char* );
BDateTime stringDateToBDate ( const char*, const char* );
BString dateTo3339String ( BDateTime );
bool withinDateRange ( BDateTime, BDateTime, BDateTime ); BDateTime feedDateToBDate(const char*);
BDateTime dateRfc3339ToBDate(const char*);
BDateTime dateRfc822ToBDate(const char*);
BDateTime stringDateToBDate(const char*, const char*);
bool isRemotePath ( BString ); BString dateTo3339String(BDateTime);
bool withinDateRange(BDateTime, BDateTime, BDateTime);
bool isRemotePath(BString);
int32 webFetch(BUrl, BDataIO*, BString*);
int32 webFetch(BUrl, BDataIO*);
int32 webFetch ( BUrl, BDataIO*, BString* );
int32 webFetch ( BUrl, BDataIO* );
#endif #endif