summaryrefslogtreecommitdiff
path: root/rssreader.c
diff options
context:
space:
mode:
authorlouis <louis.braun@gmx.de>2013-04-07 10:39:42 +0200
committerlouis <louis.braun@gmx.de>2013-04-07 10:39:42 +0200
commitfba3191de71867e91eb51cde93136fcdda64c0ab (patch)
treee99221ec2c9a7dc612b7e818c4b544a0c1e65a1d /rssreader.c
parent518e7e87332e2b53e9f3e5f9fc853abaec2b360f (diff)
downloadskin-nopacity-fba3191de71867e91eb51cde93136fcdda64c0ab.tar.gz
skin-nopacity-fba3191de71867e91eb51cde93136fcdda64c0ab.tar.bz2
Added RSS Feed support
Diffstat (limited to 'rssreader.c')
-rw-r--r--rssreader.c254
1 files changed, 254 insertions, 0 deletions
diff --git a/rssreader.c b/rssreader.c
new file mode 100644
index 0000000..d3ff151
--- /dev/null
+++ b/rssreader.c
@@ -0,0 +1,254 @@
+#include "rssreader.h"
+
+static size_t WriteXMLMemoryCallback(void* pointer, size_t size, size_t nmemb, void* xmlData) {
+ size_t realsize = size * nmemb;
+ struct XMLMemoryStruct* memStruct = (struct XMLMemoryStruct*)xmlData;
+ if (memStruct->memory)
+ memStruct->memory = (char*)realloc(memStruct->memory, memStruct->size + realsize + 1);
+ else
+ memStruct->memory = (char*)malloc(memStruct->size + realsize + 1);
+ if (memStruct->memory) {
+ memcpy (&(memStruct->memory[memStruct->size]), pointer, realsize);
+ memStruct->size += realsize;
+ memStruct->memory[memStruct->size] = 0;
+ }
+ return realsize;
+}
+
+cRssReader::cRssReader(cOsd *osd, cFont *font, cPoint position, cPoint size) {
+ this->osd = osd;
+ this->font = font;
+ pixmap = NULL;
+
+ x = position.X();
+ y = position.Y();
+
+ width = size.X();
+ height = size.Y();
+
+ xmlData.memory = 0;
+ xmlData.size = 0;
+
+ useProxy = false;
+ httpproxy = "";
+
+ separator = " +++ ";
+ currentElement = 0;
+ switchToNextMessage = false;
+}
+
+cRssReader::~cRssReader() {
+ osd->DestroyPixmap(pixmap);
+}
+
+int cRssReader::readRssURL(const char *url) {
+ CURL* my_curl_handle;
+ long code;
+ if (xmlData.memory)
+ free(xmlData.memory);
+ xmlData.memory = 0;
+ xmlData.size = 0;
+ if (curl_global_init(CURL_GLOBAL_ALL) != 0) {
+ esyslog("nopacity: Error, something went wrong with curl_global_init()");
+ return -1;
+ }
+ my_curl_handle = curl_easy_init();
+ if (!my_curl_handle) {
+ esyslog("nopacity: Error, unable to get handle from curl_easy_init()");
+ return -1;
+ }
+ if (useProxy) {
+ curl_easy_setopt(my_curl_handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
+ curl_easy_setopt(my_curl_handle, CURLOPT_PROXY, httpproxy.c_str()); // Specify HTTP proxy
+ }
+ curl_easy_setopt(my_curl_handle, CURLOPT_URL, url); // Specify URL to get
+ curl_easy_setopt(my_curl_handle, CURLOPT_FOLLOWLOCATION, 0); // don't follow redirects
+ curl_easy_setopt(my_curl_handle, CURLOPT_WRITEFUNCTION, WriteXMLMemoryCallback); // Send all data to this function
+ curl_easy_setopt(my_curl_handle, CURLOPT_WRITEDATA, (void*)&xmlData); // Pass our 'data' struct to the callback function
+ curl_easy_setopt(my_curl_handle, CURLOPT_MAXFILESIZE, 1024*1024); // Set maximum file size to get (bytes)
+ curl_easy_setopt(my_curl_handle, CURLOPT_NOPROGRESS, 1); // No progress meter
+ curl_easy_setopt(my_curl_handle, CURLOPT_NOSIGNAL, 1); // No signaling
+ curl_easy_setopt(my_curl_handle, CURLOPT_TIMEOUT, 30); // Set timeout to 30 seconds
+ curl_easy_setopt(my_curl_handle, CURLOPT_USERAGENT, NOPACITY_USERAGENT); // Some servers don't like requests that are made without a user-agent field
+
+ if (curl_easy_perform(my_curl_handle) != 0) {
+ curl_easy_cleanup(my_curl_handle); // Cleanup curl stuff
+ if (xmlData.memory) {
+ free(xmlData.memory);
+ xmlData.memory = 0;
+ xmlData.size = 0;
+ }
+ esyslog("nopacity: Error, download of '%s' failed", url);
+ return -1;
+ }
+ curl_easy_getinfo(my_curl_handle, CURLINFO_HTTP_CODE, &code);
+ if (code == 404) {
+ if (xmlData.memory)
+ free(xmlData.memory);
+ xmlData.memory = 0;
+ xmlData.size = 0;
+ }
+ curl_easy_cleanup(my_curl_handle); // Cleanup curl stuff
+
+ return xmlData.size;
+}
+
+void cRssReader::traverseTree(xmlNode * a_node, bool foundItem) {
+ xmlNode *cur_node = NULL;
+ xmlChar *node_content;
+ bool foundItemAct = false;
+ for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
+ if (cur_node->type == XML_ELEMENT_NODE) {
+ if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"item"))){
+ foundItemAct = true;
+ saveItem();
+ } else {
+ if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"title")) && foundItem){
+ node_content = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
+ if (node_content)
+ title = (const char *)node_content;
+ else
+ title = "";
+ xmlFree(node_content);
+ }
+ if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"description")) && foundItem){
+ node_content = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
+ if (node_content)
+ content = (const char *)node_content;
+ else
+ content = "";
+ xmlFree(node_content);
+ }
+ }
+ }
+ traverseTree(cur_node->children, foundItemAct);
+ }
+
+}
+
+void cRssReader::saveItem(void) {
+ if (!title.length())
+ return;
+ RssElement rssElement;
+ rssElement.title = title;
+ rssElement.content = content;
+ int width = font->Width(title.c_str()) + font->Width(": ") + font->Width(content.c_str()) + font->Width(separator.c_str());
+ rssElement.width = width;
+ rssElements.push_back(rssElement);
+}
+
+void cRssReader::saveRss(void) {
+ xmlNode *root_element = NULL;
+ root_element = xmlDocGetRootElement(doc);
+ traverseTree(root_element, false);
+ saveItem();
+ xmlFreeDoc(doc);
+}
+
+void cRssReader::createPixmap(void) {
+ if (pixmap)
+ osd->DestroyPixmap(pixmap);
+ pixmap = osd->CreatePixmap(7, cRect(x, y, width, height), cRect(0, 0, rssElements[currentElement].width, height));
+ pixmap->Fill(clrTransparent);
+ pixmap->SetAlpha(0);
+}
+
+void cRssReader::drawText(void) {
+ int currentX = 5;
+ int textY = (height - font->Height()) / 2;
+ cString text = cString::sprintf("%s: ", rssElements[currentElement].title.c_str());
+ pixmap->DrawText(cPoint(currentX, textY), *text, Theme.Color(clrMenuFontMenuItemHigh), clrTransparent, font);
+ currentX += font->Width(*text);
+ text = cString::sprintf("%s%s", rssElements[currentElement].content.c_str(), separator.c_str());
+ pixmap->DrawText(cPoint(currentX, textY), *text, Theme.Color(clrMenuFontMenuItem), clrTransparent, font);
+}
+
+void cRssReader::DoSleep(int duration) {
+ int sleepSlice = 10;
+ for (int i = 0; Running() && (i*sleepSlice < duration); i++)
+ cCondWait::SleepMs(sleepSlice);
+}
+
+void cRssReader::Action(void) {
+ int success = readRssURL(feedUrl.c_str());
+ if (success < 1)
+ return;
+ if (!strstr(xmlData.memory, "rss"))
+ return;
+ doc = NULL;
+ doc = xmlReadMemory(xmlData.memory, strlen(xmlData.memory), "noname.xml", NULL, 0);
+ if (doc == NULL) {
+ return;
+ }
+ saveRss();
+
+ int numElements = rssElements.size();
+ int scrollDelay = config.rssScrollDelay * 1000;
+ int drawPortX;
+ int FrameTime = config.rssScrollFrameTime;
+ int maxX;
+ bool doSleep;
+
+ createPixmap();
+ drawText();
+ fadeInOut(true);
+ DoSleep(scrollDelay);
+ doSleep = false;
+ maxX = pixmap->DrawPort().Width() - pixmap->ViewPort().Width();
+
+ while (Running()) {
+ if (doSleep) {
+ fadeInOut(true);
+ DoSleep(scrollDelay);
+ doSleep = false;
+ }
+ uint64_t Now = cTimeMs::Now();
+ cPixmap::Lock();
+ drawPortX = pixmap->DrawPort().X();
+ drawPortX -= 1;
+ cPixmap::Unlock();
+ if ((abs(drawPortX) > maxX) || switchToNextMessage) {
+ if (!switchToNextMessage)
+ DoSleep(scrollDelay);
+ else
+ switchToNextMessage = false;
+ fadeInOut(false);
+ currentElement = (currentElement + 1)%numElements;
+ createPixmap();
+ drawText();
+ maxX = pixmap->DrawPort().Width() - pixmap->ViewPort().Width();
+ drawPortX = 0;
+ doSleep = true;
+ }
+ cPixmap::Lock();
+ if (Running())
+ pixmap->SetDrawPortPoint(cPoint(drawPortX, 0));
+ cPixmap::Unlock();
+ int Delta = cTimeMs::Now() - Now;
+ if (Running())
+ osd->Flush();
+ if (Running() && (Delta < FrameTime))
+ cCondWait::SleepMs(FrameTime - Delta);
+ }
+
+}
+
+void cRssReader::fadeInOut(bool fadeIn) {
+ int frameTime = 50;
+ int alpha = (fadeIn)?0:225;
+ for (int i=0; i<10; i++) {
+ if (Running()) {
+ if (fadeIn)
+ alpha += 26;
+ else
+ alpha -= 26;
+ if (alpha < 0) alpha = 0;
+ if (alpha > 255) alpha = 255;
+ cPixmap::Lock();
+ pixmap->SetAlpha(alpha);
+ cPixmap::Unlock();
+ osd->Flush();
+ }
+ DoSleep(frameTime);
+ }
+}