2020-07-08 03:20:03 -05:00
|
|
|
#include <tinyxml2.h>
|
2020-11-16 20:32:58 -06:00
|
|
|
#include "App.h"
|
2020-07-08 03:20:03 -05:00
|
|
|
#include "Entry.h"
|
|
|
|
#include "Config.h"
|
|
|
|
#include "Util.h"
|
|
|
|
#include "Feed.h"
|
|
|
|
|
2020-11-16 20:32:58 -06:00
|
|
|
Feed::Feed ( BString path )
|
2020-07-08 03:20:03 -05:00
|
|
|
{
|
2020-07-13 12:31:52 -05:00
|
|
|
title = BString( "Untitled Feed" );
|
|
|
|
description = BString( "Nondescript, N/A." );
|
2020-07-08 03:20:03 -05:00
|
|
|
homeUrl = BString("");
|
|
|
|
xmlUrl = BString("");
|
2020-08-02 02:05:20 -05:00
|
|
|
updated = true;
|
2020-11-16 21:32:06 -06:00
|
|
|
fetched = false;
|
|
|
|
inputPath = path;
|
|
|
|
SetCachePath( path );
|
2020-07-08 03:20:03 -05:00
|
|
|
}
|
|
|
|
|
2020-08-11 13:29:49 -05:00
|
|
|
Feed::Feed ( )
|
|
|
|
{
|
2020-07-08 04:43:35 -05:00
|
|
|
title = BString("");
|
|
|
|
description = BString("");
|
|
|
|
homeUrl = BString("");
|
|
|
|
xmlUrl = BString("");
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
2020-08-14 14:00:07 -05:00
|
|
|
void
|
2020-11-16 20:32:58 -06:00
|
|
|
Feed::Parse ( )
|
2020-08-14 14:00:07 -05:00
|
|
|
{
|
2020-11-16 21:32:06 -06:00
|
|
|
BFile* feedFile = new BFile( GetCachePath().String(), B_READ_ONLY );
|
2020-08-14 14:00:07 -05:00
|
|
|
time_t tt_lastDate = 0;
|
|
|
|
BDateTime attrLastDate = BDateTime();
|
|
|
|
|
|
|
|
feedFile->ReadAttr( "LastDate", B_TIME_TYPE, 0, &tt_lastDate, sizeof(time_t) );
|
2020-11-16 20:32:58 -06:00
|
|
|
if ( tt_lastDate > 0 && ((App*)be_app)->cfg->updateFeeds == true ) {
|
2020-08-14 14:00:07 -05:00
|
|
|
attrLastDate.SetTime_t( tt_lastDate );
|
|
|
|
minDate = attrLastDate;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------
|
|
|
|
|
2020-11-16 21:32:06 -06:00
|
|
|
// -------------------------------------
|
2020-08-02 02:05:20 -05:00
|
|
|
|
2020-11-16 21:32:06 -06:00
|
|
|
// Download a remote feed's XML to the cache path.
|
2020-08-02 02:05:20 -05:00
|
|
|
BString
|
2020-11-16 21:32:06 -06:00
|
|
|
Feed::FetchRemoteFeed ( )
|
2020-08-02 02:05:20 -05:00
|
|
|
{
|
2020-11-16 21:32:06 -06:00
|
|
|
BUrl givenUrl = BUrl( inputPath );
|
2020-08-14 01:59:15 -05:00
|
|
|
time_t tt_lastDate = 0;
|
|
|
|
BDateTime* lastDate = new BDateTime();
|
2020-08-02 02:05:20 -05:00
|
|
|
BString* newHash = new BString();
|
|
|
|
char oldHash[41];
|
|
|
|
|
2020-11-16 21:32:06 -06:00
|
|
|
BFile* cacheFile = new BFile( GetCachePath(), B_READ_WRITE | B_CREATE_FILE );
|
2020-07-13 12:31:52 -05:00
|
|
|
|
2020-08-14 01:59:15 -05:00
|
|
|
cacheFile->ReadAttr( "LastHash", B_STRING_TYPE, 0, oldHash, 41 );
|
2020-08-02 02:05:20 -05:00
|
|
|
|
2020-11-16 20:32:58 -06:00
|
|
|
if ( ((App*)be_app)->cfg->verbose )
|
2020-11-16 21:32:06 -06:00
|
|
|
printf( "Saving %s...\n", inputPath.String() );
|
2020-08-02 02:05:20 -05:00
|
|
|
|
2020-11-16 21:32:06 -06:00
|
|
|
webFetch( BUrl(inputPath), cacheFile, newHash );
|
2020-08-02 02:05:20 -05:00
|
|
|
|
2020-08-11 13:29:49 -05:00
|
|
|
cacheFile->WriteAttr( "LastHash", B_STRING_TYPE, 0,
|
2020-08-02 02:05:20 -05:00
|
|
|
newHash->String(), newHash->CountChars() );
|
|
|
|
|
|
|
|
if ( *(newHash) == BString(oldHash) )
|
|
|
|
updated = false;
|
2020-07-13 12:31:52 -05:00
|
|
|
|
2020-11-16 21:32:06 -06:00
|
|
|
fetched = true;
|
|
|
|
return GetCachePath();
|
2020-07-13 12:31:52 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
2020-11-16 21:32:06 -06:00
|
|
|
// return whether or not the feed's given URI/path is remote.
|
|
|
|
bool
|
|
|
|
Feed::IsRemote ( )
|
|
|
|
{
|
|
|
|
return isRemotePath( inputPath );
|
|
|
|
}
|
|
|
|
|
|
|
|
// return whether or not the feed seems to have been updated
|
|
|
|
bool
|
|
|
|
Feed::IsUpdated ( )
|
|
|
|
{
|
|
|
|
return updated;
|
|
|
|
}
|
|
|
|
|
|
|
|
// return whether or not feed is RSS
|
2020-07-08 04:43:35 -05:00
|
|
|
bool
|
|
|
|
Feed::IsRss ( )
|
|
|
|
{
|
2020-11-16 21:32:06 -06:00
|
|
|
EnsureCached();
|
2020-07-08 04:43:35 -05:00
|
|
|
tinyxml2::XMLDocument xml;
|
2020-11-16 21:32:06 -06:00
|
|
|
xml.LoadFile( GetCachePath().String() );
|
2020-07-08 04:43:35 -05:00
|
|
|
|
|
|
|
if ( xml.FirstChildElement("rss") )
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-11-16 21:32:06 -06:00
|
|
|
// return whether or not feed is Atom
|
2020-07-08 04:43:35 -05:00
|
|
|
bool
|
|
|
|
Feed::IsAtom ( )
|
|
|
|
{
|
|
|
|
tinyxml2::XMLDocument xml;
|
2020-11-16 21:32:06 -06:00
|
|
|
xml.LoadFile( GetCachePath().String() );
|
2020-07-08 04:43:35 -05:00
|
|
|
|
|
|
|
if ( xml.FirstChildElement("feed") )
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
2020-11-16 21:32:06 -06:00
|
|
|
// ensure the feed XML is available at the cache path.
|
|
|
|
// if necessary, download it.
|
|
|
|
void
|
|
|
|
Feed::EnsureCached ( )
|
|
|
|
{
|
|
|
|
if ( IsRemote() && fetched == false )
|
|
|
|
FetchRemoteFeed();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return the 'cachePath' (location of XML file locally)
|
|
|
|
BString
|
|
|
|
Feed::GetCachePath ( )
|
|
|
|
{
|
|
|
|
if ( cachePath == NULL )
|
|
|
|
SetCachePath( inputPath );
|
|
|
|
return cachePath;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Select a 'cachePath' (location of XML file locally)
|
|
|
|
// For remote files, a cache file is created in ~/config/cache/Pogger/ by default
|
|
|
|
// For local files, the same local file is used.
|
|
|
|
BString
|
|
|
|
Feed::SetCachePath ( BString givenPath )
|
|
|
|
{
|
|
|
|
BUrl givenUrl = BUrl( givenPath );
|
|
|
|
BString protocol = givenUrl.Protocol().String();
|
|
|
|
|
|
|
|
if ( protocol == NULL && givenUrl.UrlString() != NULL ) {
|
|
|
|
cachePath = givenPath;
|
|
|
|
return givenPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
BString splitName = givenUrl.Host( );
|
|
|
|
splitName.Append( givenUrl.Path() );
|
|
|
|
splitName.ReplaceAll("/", "_");
|
|
|
|
|
|
|
|
BString filename = ((App*)be_app)->cfg->cacheDir;
|
|
|
|
filename.Append(splitName);
|
|
|
|
|
|
|
|
cachePath = filename;
|
|
|
|
return filename;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// count the amount of siblings to an element of given type name
|
2020-07-08 04:43:35 -05:00
|
|
|
int
|
|
|
|
Feed::xmlCountSiblings ( tinyxml2::XMLElement* xsibling, const char* sibling_name )
|
2020-07-08 03:20:03 -05:00
|
|
|
{
|
2020-07-08 04:43:35 -05:00
|
|
|
int count = 0;
|
|
|
|
while ( xsibling ) {
|
|
|
|
count++;
|
|
|
|
xsibling = xsibling->NextSiblingElement(sibling_name);
|
|
|
|
}
|
|
|
|
return count;
|
2020-07-08 03:20:03 -05:00
|
|
|
}
|
|
|
|
|
2020-07-08 04:43:35 -05:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
2020-11-16 21:32:06 -06:00
|
|
|
// add the given entry to the feed, if appropriate
|
2020-08-14 01:59:15 -05:00
|
|
|
bool
|
2020-11-16 20:32:58 -06:00
|
|
|
Feed::AddEntry ( Entry* newEntry )
|
2020-08-14 01:59:15 -05:00
|
|
|
{
|
2020-11-16 20:32:58 -06:00
|
|
|
Config* cfg = ((App*)be_app)->cfg;
|
2020-08-14 12:34:09 -05:00
|
|
|
if ( !withinDateRange( cfg->minDate, newEntry->date, cfg->maxDate ) ||
|
|
|
|
!withinDateRange( minDate, newEntry->date, maxDate ) )
|
2020-08-14 01:59:15 -05:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if ( cfg->verbose == true )
|
|
|
|
printf( "\t%s\n", newEntry->title.String() );
|
|
|
|
entries.AddItem( newEntry );
|
|
|
|
return true;
|
|
|
|
}
|
2020-11-16 21:32:06 -06:00
|
|
|
BList Feed::GetEntries ( ) { return entries; }
|
2020-08-14 01:59:15 -05:00
|
|
|
|
2020-07-08 03:20:03 -05:00
|
|
|
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;
|
|
|
|
}
|
2020-11-16 21:32:06 -06:00
|
|
|
BString Feed::GetTitle ( ) { return title; }
|
2020-07-08 03:20:03 -05:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2020-11-16 21:32:06 -06:00
|
|
|
BString Feed::GetDesc ( ) { return description; }
|
2020-07-08 03:20:03 -05:00
|
|
|
|
2020-11-16 21:32:06 -06:00
|
|
|
// set a feed's «home URL»
|
2020-07-08 03:20:03 -05:00
|
|
|
bool Feed::SetHomeUrl ( const char* homepageStr ) {
|
|
|
|
if ( homepageStr != NULL ) homeUrl = BString( homepageStr );
|
|
|
|
else return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool Feed::SetHomeUrl ( tinyxml2::XMLElement* elem ) {
|
|
|
|
if ( elem != NULL ) return SetHomeUrl( elem->GetText() );
|
|
|
|
else return false;
|
|
|
|
}
|
2020-11-16 21:32:06 -06:00
|
|
|
BString Feed::GetHomeUrl ( ) { return homeUrl; }
|
2020-07-08 03:20:03 -05:00
|
|
|
|
2020-11-16 21:32:06 -06:00
|
|
|
// set the update time for a feed
|
2020-07-08 03:20:03 -05:00
|
|
|
bool Feed::SetDate ( const char* dateCStr ) {
|
|
|
|
if ( dateCStr == NULL )
|
|
|
|
return false;
|
|
|
|
BDateTime newDate = feedDateToBDate( dateCStr );
|
|
|
|
if ( newDate == NULL )
|
|
|
|
return false;
|
|
|
|
date = newDate;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool Feed::SetDate ( tinyxml2::XMLElement* elem ) {
|
|
|
|
if ( elem != NULL ) return SetDate( elem->GetText() );
|
|
|
|
else return false;
|
|
|
|
}
|
2020-11-16 21:32:06 -06:00
|
|
|
BDateTime Feed::GetDate ( ) { return date; }
|
2020-07-08 04:43:35 -05:00
|
|
|
|