rss-cli/src/rss.cpp

611 lines
14 KiB
C++
Raw Normal View History

2021-07-24 01:17:22 +00:00
///////////////////////////////////////////////////////////////////////////////
// Tyler Perkins
// 7-23-21
// rss implementation
//
#include "rss.hpp"
using namespace rss_utils;
rss::rss() {
2021-07-25 17:40:52 +00:00
_uri = "";
_ok = false;
_item_node = nullptr;
2021-07-24 01:17:22 +00:00
}
rss::rss(const std::string& rss_uri, bool perf_update){
2021-07-25 17:40:52 +00:00
_uri = rss_uri;
_item_node = nullptr;
_ok = false;
2021-07-24 01:17:22 +00:00
if(perf_update)
update();
}
rss::rss(const char* rss_uri, bool perf_update){
2021-07-25 17:40:52 +00:00
_uri = std::string(rss_uri);
_ok = false;
_item_node = nullptr;
2021-07-24 01:17:22 +00:00
if(perf_update)
update();
}
rss::rss(const rss& rhs){
2021-07-25 17:40:52 +00:00
_uri = rhs._uri;
_ok = false;
_item_node = nullptr;
2021-07-24 01:17:22 +00:00
update();
}
rss::~rss(){
2021-07-25 17:40:52 +00:00
_doc.clear();
2021-07-24 01:17:22 +00:00
}
rss& rss::operator=(const rss& rhs){
if(this != &rhs){
2021-07-25 17:40:52 +00:00
_uri = rhs._uri;
_ok = false;
_item_node = nullptr;
2021-07-24 01:17:22 +00:00
update();
}
return *this;
}
rss* rss::clone() const {
rss* clone = new rss(*this);
return clone;
}
2021-07-25 17:40:52 +00:00
bool rss::isOk() const { return _ok; }
2021-07-24 01:17:22 +00:00
void rss::setURI(const std::string& rss_uri, bool perf_update) {
2021-07-25 17:40:52 +00:00
_uri = rss_uri;
_ok = false;
2021-07-24 01:17:22 +00:00
if(perf_update)
update();
}
void rss::setURI(const char* rss_uri, bool perf_update) {
2021-07-25 17:40:52 +00:00
_uri = std::string(rss_uri);
_ok = false;
2021-07-24 01:17:22 +00:00
if(perf_update)
update();
}
2021-07-25 17:40:52 +00:00
std::string rss::getURI() const { return _uri; }
2021-07-24 01:17:22 +00:00
bool rss::update() {
std::string result;
2021-07-26 23:24:55 +00:00
if(_uri == "-"){
std::getline(std::cin, result);
return parse(result);
} else {
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if(curl){
curl_easy_setopt(curl, CURLOPT_URL, _uri.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, rss_utils::write_to_string);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &result);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
if(res == CURLE_OK){
return parse(result);
} else {
std::cerr << "curl_easy_perform(curl) failed: "
<< curl_easy_strerror(res) << std::endl;
}
2021-07-24 01:17:22 +00:00
}
2021-07-26 23:24:55 +00:00
_ok = false;
return false;
2021-07-24 01:17:22 +00:00
}
}
std::string rss::getTitle() const {
2021-07-25 17:40:52 +00:00
if(!_ok)
2021-07-24 01:17:22 +00:00
return "";
2021-07-25 17:40:52 +00:00
rapidxml::xml_node<> *tmp = _item_node->first_node("title");
2021-07-24 01:17:22 +00:00
if(tmp == 0)
return "";
2021-07-25 23:07:40 +00:00
return cdata_to_string(tmp);
2021-07-24 01:17:22 +00:00
}
std::string rss::getLink() const {
2021-07-25 17:40:52 +00:00
if(!_ok)
2021-07-24 01:17:22 +00:00
return "";
2021-07-25 17:40:52 +00:00
rapidxml::xml_node<> *tmp = _item_node->first_node("link");
2021-07-24 01:17:22 +00:00
if(tmp == 0)
return "";
2021-07-25 23:07:40 +00:00
return cdata_to_string(tmp);
2021-07-24 01:17:22 +00:00
}
std::string rss::getDescription() const {
2021-07-25 17:40:52 +00:00
if(!_ok)
2021-07-24 01:17:22 +00:00
return "";
2021-07-25 17:40:52 +00:00
rapidxml::xml_node<> *tmp = _item_node->first_node("description");
2021-07-24 01:17:22 +00:00
if(tmp == 0)
return "";
2021-07-25 23:07:40 +00:00
return cdata_to_string(tmp);
2021-07-24 01:17:22 +00:00
}
std::string rss::getLanguage() const {
2021-07-25 17:40:52 +00:00
if(!_ok)
2021-07-24 01:17:22 +00:00
return "";
2021-07-25 17:40:52 +00:00
rapidxml::xml_node<> *tmp = _item_node->first_node("language");
2021-07-24 01:17:22 +00:00
if(tmp == 0)
return "";
2021-07-25 23:07:40 +00:00
return cdata_to_string(tmp);
2021-07-24 01:17:22 +00:00
}
std::string rss::getWebMaster() const {
2021-07-25 17:40:52 +00:00
if(!_ok)
2021-07-24 01:17:22 +00:00
return "";
2021-07-25 17:40:52 +00:00
rapidxml::xml_node<> *tmp = _item_node->first_node("webMaster");
2021-07-24 01:17:22 +00:00
if(tmp == 0)
return "";
2021-07-25 23:07:40 +00:00
return cdata_to_string(tmp);
2021-07-24 01:17:22 +00:00
}
std::string rss::getCopyright() const {
2021-07-25 17:40:52 +00:00
if(!_ok)
2021-07-24 01:17:22 +00:00
return "";
2021-07-25 17:40:52 +00:00
rapidxml::xml_node<> *tmp = _item_node->first_node("copyright");
2021-07-24 01:17:22 +00:00
if(tmp == 0)
return "";
2021-07-25 23:07:40 +00:00
return cdata_to_string(tmp);
2021-07-24 01:17:22 +00:00
}
std::string rss::getPubDate() const {
2021-07-25 17:40:52 +00:00
if(!_ok)
2021-07-24 01:17:22 +00:00
return "";
2021-07-25 17:40:52 +00:00
rapidxml::xml_node<> *tmp = _item_node->first_node("pubDate");
2021-07-24 01:17:22 +00:00
if(tmp == 0)
return "";
2021-07-25 23:07:40 +00:00
return cdata_to_string(tmp);
2021-07-24 01:17:22 +00:00
}
2021-07-24 03:24:20 +00:00
std::string rss::getManagingEditor() const {
2021-07-25 17:40:52 +00:00
if(!_ok)
2021-07-24 03:24:20 +00:00
return "";
2021-07-25 17:40:52 +00:00
rapidxml::xml_node<> *tmp = _item_node->first_node("managingEditor");
2021-07-24 03:24:20 +00:00
if(tmp == 0)
return "";
2021-07-25 23:07:40 +00:00
return cdata_to_string(tmp);
2021-07-24 03:24:20 +00:00
}
std::string rss::getGenerator() const {
2021-07-25 17:40:52 +00:00
if(!_ok)
2021-07-24 03:24:20 +00:00
return "";
2021-07-25 17:40:52 +00:00
rapidxml::xml_node<> *tmp = _item_node->first_node("generator");
2021-07-24 03:24:20 +00:00
if(tmp == 0)
return "";
2021-07-25 23:07:40 +00:00
return cdata_to_string(tmp);
2021-07-24 03:24:20 +00:00
}
std::string rss::getDocs() const {
2021-07-25 17:40:52 +00:00
if(!_ok)
2021-07-24 03:24:20 +00:00
return "";
2021-07-25 17:40:52 +00:00
rapidxml::xml_node<> *tmp = _item_node->first_node("docs");
2021-07-24 03:24:20 +00:00
if(tmp == 0)
return "";
2021-07-25 23:07:40 +00:00
return cdata_to_string(tmp);
2021-07-24 03:24:20 +00:00
}
std::string rss::getTTL() const {
2021-07-25 17:40:52 +00:00
if(!_ok)
2021-07-24 03:24:20 +00:00
return "";
2021-07-25 17:40:52 +00:00
rapidxml::xml_node<> *tmp = _item_node->first_node("ttl");
2021-07-24 03:24:20 +00:00
if(tmp == 0)
return "";
2021-07-25 23:07:40 +00:00
return cdata_to_string(tmp);
2021-07-24 03:24:20 +00:00
}
std::string rss::getLastBuildDate() const {
2021-07-25 17:40:52 +00:00
if(!_ok)
2021-07-24 03:24:20 +00:00
return "";
2021-07-25 17:40:52 +00:00
rapidxml::xml_node<> *tmp = _item_node->first_node("lastBuildDate");
2021-07-24 03:24:20 +00:00
if(tmp == 0)
return "";
2021-07-25 23:07:40 +00:00
return cdata_to_string(tmp);
2021-07-24 03:24:20 +00:00
}
2021-07-26 00:00:12 +00:00
std::string rss::getImageURL() const {
if(!_ok)
return "";
rapidxml::xml_node<> *tmp = _item_node->first_node("image");
if(tmp == 0)
return "";
tmp = tmp->first_node("url");
if(tmp == 0)
return "";
return cdata_to_string(tmp);
}
std::string rss::getImageTitle() const {
if(!_ok)
return "";
rapidxml::xml_node<> *tmp = _item_node->first_node("image");
if(tmp == 0)
return "";
tmp = tmp->first_node("title");
if(tmp == 0)
return "";
return cdata_to_string(tmp);
}
2021-07-26 00:58:42 +00:00
std::string rss::getImageLink() const {
2021-07-26 00:00:12 +00:00
if(!_ok)
return "";
rapidxml::xml_node<> *tmp = _item_node->first_node("image");
if(tmp == 0)
return "";
tmp = tmp->first_node("link");
if(tmp == 0)
return "";
return cdata_to_string(tmp);
}
2021-07-26 00:58:42 +00:00
int rss::getImageWidth() const {
2021-07-26 00:00:12 +00:00
if(!_ok)
return 0;
rapidxml::xml_node<> *tmp = _item_node->first_node("image");
if(tmp == 0)
return 0;
tmp = tmp->first_node("width");
if(tmp == 0)
return 0;
return atoi(tmp->value());
}
2021-07-26 00:58:42 +00:00
int rss::getImageHeight() const {
2021-07-26 00:00:12 +00:00
if(!_ok)
return 0;
rapidxml::xml_node<> *tmp = _item_node->first_node("image");
if(tmp == 0)
return 0;
tmp = tmp->first_node("height");
if(tmp == 0)
return 0;
return atoi(tmp->value());
}
2021-07-26 00:58:42 +00:00
std::string rss::getCloudDomain() const {
if(!_ok)
return "";
rapidxml::xml_node<> *tmp = _item_node->first_node("cloud");
if(tmp == 0)
return "";
rapidxml::xml_attribute<> *attr = tmp->first_attribute("domain");
if(attr == 0)
return "";
return attr->value();
}
int rss::getCloudPort() const {
if(!_ok)
return 0;
rapidxml::xml_node<> *tmp = _item_node->first_node("cloud");
if(tmp == 0)
return 0;
rapidxml::xml_attribute<> *attr = tmp->first_attribute("port");
if(attr == 0)
return 0;
return atoi(attr->value());
}
std::string rss::getCloudPath() const {
if(!_ok)
return "";
rapidxml::xml_node<> *tmp = _item_node->first_node("cloud");
if(tmp == 0)
return "";
rapidxml::xml_attribute<> *attr = tmp->first_attribute("path");
if(attr == 0)
return "";
return attr->value();
}
std::string rss::getCloudRegisterProcedure() const {
2021-07-26 00:58:42 +00:00
if(!_ok)
return "";
rapidxml::xml_node<> *tmp = _item_node->first_node("cloud");
if(tmp == 0)
return "";
rapidxml::xml_attribute<> *attr = tmp->first_attribute("registerProcedure");
if(attr == 0)
return "";
return attr->value();
}
std::string rss::getCloudProtocol() const {
2021-07-26 00:58:42 +00:00
if(!_ok)
return "";
rapidxml::xml_node<> *tmp = _item_node->first_node("cloud");
if(tmp == 0)
return "";
rapidxml::xml_attribute<> *attr = tmp->first_attribute("protocol");
if(attr == 0)
return "";
return attr->value();
}
2021-07-25 17:40:52 +00:00
int rss::getItemCount() const {
if(!_ok)
return -1;
2021-07-24 01:17:22 +00:00
2021-07-25 17:40:52 +00:00
return _items.size();
}
std::vector<item> rss::getItems() {
if(!_ok)
return std::vector<item>();
if(!_items.empty())
return _items;
//items is empty, have not processed the items yet
std::vector<rapidxml::xml_node<>*> items;
items = parseItems();
for(auto it = items.begin(); it != items.end(); ++it){
item i(*it);
_items.push_back(i);
}
return _items;
}
item& rss::getItem(const int index) {
getItems();
return _items[index];
}
const item& rss::getItem(const int index) const {
return _items[index];
}
item& rss::operator[](const int index) {
return getItem(index);
}
const item& rss::operator[](const int index) const {
return getItem(index);
}
std::vector<rapidxml::xml_node<>*> rss::parseItems() {
std::vector<rapidxml::xml_node<>*> items;
if(!_ok)
2021-07-24 01:17:22 +00:00
return items;
2021-07-25 17:40:52 +00:00
rapidxml::xml_node<> *first_item = _item_node->first_node("item");
2021-07-24 01:17:22 +00:00
//there are no items, return empty vector
if(first_item == 0)
return items;
2021-07-25 17:40:52 +00:00
for(; first_item != NULL; first_item = first_item->next_sibling())
items.push_back(first_item);
2021-07-24 01:17:22 +00:00
return items;
}
bool rss::parse(const std::string& rss_str){
2021-07-25 17:40:52 +00:00
_ok = true;
2021-07-24 01:17:22 +00:00
//parse, check for errors in xml doc
try {
2021-07-25 17:40:52 +00:00
_doc.parse<0>(_doc.allocate_string(rss_str.c_str()));
2021-07-24 01:17:22 +00:00
} catch (const std::runtime_error& e){
std::cerr << "rss::parse() runtime error: " << e.what() << std::endl;
2021-07-25 17:40:52 +00:00
_ok = false;
2021-07-24 01:17:22 +00:00
} catch (const rapidxml::parse_error& e){
std::cerr << "rss::parse() error with file: " << e.what() << std::endl;
2021-07-25 17:40:52 +00:00
_ok = false;
2021-07-24 01:17:22 +00:00
}
//verify that it is an rss file
2021-07-25 17:40:52 +00:00
rapidxml::xml_node<> *tmp = _doc.first_node("rss");
2021-07-24 01:17:22 +00:00
if(tmp == NULL){
std::cerr << "rss::parse() error with file: XML is not an rss feed!" << std::endl;
2021-07-25 17:40:52 +00:00
_ok = false;
2021-07-24 01:17:22 +00:00
} else {
tmp = tmp->first_node("channel");
if(tmp == NULL){
std::cerr << "rss::parse() error with file: RSS feed has no channels!"
<< std::endl;
2021-07-25 17:40:52 +00:00
_ok = false;
2021-07-24 01:17:22 +00:00
}
}
2021-07-25 17:40:52 +00:00
if(_ok){
_item_node = tmp;
2021-07-24 01:17:22 +00:00
}
2021-07-25 17:40:52 +00:00
return _ok;
2021-07-24 01:17:22 +00:00
}
2021-07-25 23:07:40 +00:00
std::string rss::cdata_to_string(const rapidxml::xml_node<>* node) const{
//this will dig till were past the cdata
const rapidxml::xml_node<>* tmp = node;
while(tmp->value()[0] == '\0'){ //if string is empty
tmp = tmp->first_node();
if(tmp == NULL)
return "";
}
return tmp->value();
}
2021-07-24 01:17:22 +00:00
size_t rss_utils::write_to_string(void* ptr, size_t size, size_t nmemb, std::string* s){
s->append(static_cast<char *>(ptr), size * nmemb);
return size * nmemb;
}
2021-07-25 17:40:52 +00:00
2021-07-25 23:07:40 +00:00
std::string item::cdata_to_string(const rapidxml::xml_node<>* node) const{
//this will dig till were past the cdata
const rapidxml::xml_node<>* tmp = node;
while(tmp->value()[0] == '\0'){ //if string is empty
tmp = tmp->first_node();
if(tmp == NULL)
return "";
}
return tmp->value();
}
2021-07-25 17:40:52 +00:00
item::item() {}
item::item(rapidxml::xml_node<>* node){
_item = node;
}
item::item(const item& rhs){
_item = rhs._item;
}
item::~item() {}
item& item::operator=(const item& rhs){
if(this != &rhs){
_item = rhs._item;
}
return *this;
}
item* item::clone() const {
item* clone = new item(*this);
return clone;
}
std::string item::getTitle() const {
rapidxml::xml_node<>* tmp = _item->first_node("title");
if(tmp == 0)
return "";
2021-07-25 23:07:40 +00:00
return cdata_to_string(tmp);
2021-07-25 17:40:52 +00:00
}
std::string item::getLink() const {
rapidxml::xml_node<>* tmp = _item->first_node("link");
if(tmp == 0)
return "";
2021-07-25 23:07:40 +00:00
return cdata_to_string(tmp);
2021-07-25 17:40:52 +00:00
}
std::string item::getDescription() const {
rapidxml::xml_node<>* tmp = _item->first_node("description");
if(tmp == 0)
return "";
2021-07-25 23:07:40 +00:00
return cdata_to_string(tmp);
2021-07-25 17:40:52 +00:00
}
std::string item::getAuthor() const {
rapidxml::xml_node<>* tmp = _item->first_node("author");
if(tmp == 0)
return "";
2021-07-25 23:07:40 +00:00
return cdata_to_string(tmp);
2021-07-25 17:40:52 +00:00
}
std::string item::getCategory() const {
rapidxml::xml_node<>* tmp = _item->first_node("category");
if(tmp == 0)
return "";
2021-07-25 23:07:40 +00:00
return cdata_to_string(tmp);
2021-07-25 17:40:52 +00:00
}
std::string item::getComments() const {
rapidxml::xml_node<>* tmp = _item->first_node("comments");
if(tmp == 0)
return "";
2021-07-25 23:07:40 +00:00
return cdata_to_string(tmp);
2021-07-25 17:40:52 +00:00
}
std::string item::getGuid() const {
rapidxml::xml_node<>* tmp = _item->first_node("guid");
if(tmp == 0)
return "";
2021-07-25 23:07:40 +00:00
return cdata_to_string(tmp);
2021-07-25 17:40:52 +00:00
}
2021-07-25 23:50:30 +00:00
bool item::getGuidPermaLink() const {
rapidxml::xml_node<>* tmp = _item->first_node("guid");
if(tmp == 0)
return false;
rapidxml::xml_attribute<>* attr = tmp->first_attribute("isPermaLink");
if(attr == 0)
return false;
else if(attr->value() == std::string("true"))
2021-07-26 00:58:42 +00:00
return true;
2021-07-25 23:50:30 +00:00
return false;
}
2021-07-25 17:40:52 +00:00
std::string item::getPubDate() const {
rapidxml::xml_node<>* tmp = _item->first_node("pubDate");
if(tmp == 0)
return "";
2021-07-25 23:07:40 +00:00
return cdata_to_string(tmp);
2021-07-25 17:40:52 +00:00
}
std::string item::getSource() const {
rapidxml::xml_node<>* tmp = _item->first_node("source");
if(tmp == 0)
return "";
2021-07-25 23:07:40 +00:00
return cdata_to_string(tmp);
2021-07-25 17:40:52 +00:00
}
2021-07-25 23:50:30 +00:00
std::string item::getEnclosureURL() const {
rapidxml::xml_node<>* tmp = _item->first_node("enclosure");
if(tmp == 0)
return "";
rapidxml::xml_attribute<>* attr = tmp->first_attribute("url");
if(attr == 0)
return "";
2021-07-26 00:58:42 +00:00
return attr->value();
2021-07-25 23:50:30 +00:00
}
std::string item::getEnclosureType() const {
rapidxml::xml_node<>* tmp = _item->first_node("enclosure");
if(tmp == 0)
return "";
rapidxml::xml_attribute<>* attr = tmp->first_attribute("type");
if(attr == 0)
return "";
2021-07-26 00:58:42 +00:00
return attr->value();
2021-07-25 23:50:30 +00:00
}
int item::getEnclosureLength() const {
rapidxml::xml_node<>* tmp = _item->first_node("enclosure");
if(tmp == 0)
return -1;
rapidxml::xml_attribute<>* attr = tmp->first_attribute("length");
if(attr == 0)
return -1;
2021-07-26 00:58:42 +00:00
return atoi(attr->value());
2021-07-25 23:50:30 +00:00
}