#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); } }