diff -Nur xmltv2vdr/dist/tvm2xmltv/Makefile xmltv2vdr-n/dist/tvm2xmltv/Makefile --- xmltv2vdr/dist/tvm2xmltv/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ xmltv2vdr-n/dist/tvm2xmltv/Makefile 2011-07-10 10:11:33.000000000 +0200 @@ -0,0 +1,84 @@ +# +# Makefile for tvm2xmltv +# + +### The C++ compiler and options: + +CXX ?= g++ +CXXFLAGS ?= -g -rdynamic -O2 -Wall -Wextra -Woverloaded-virtual -Wno-parentheses +PKG-CONFIG ?= pkg-config +STRIP ?= strip + +### Includes and Defines (add further entries here): + +PKG-LIBS += libxml-2.0 libxslt libexslt libcurl +PKG-INCLUDES += libxml-2.0 libxslt libexslt libcurl + +DEFINES += -D_GNU_SOURCE +DEFINES += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE +DEFINES += -D__STDC_CONSTANT_MACROS -D__USE_XOPEN_EXTENDED + +INCLUDES += $(shell $(PKG-CONFIG) --cflags $(PKG-INCLUDES)) +LIBS += $(shell $(PKG-CONFIG) --libs $(PKG-LIBS)) +LIBS += -lz + +INCLUDES += -I.. + +### directory environment + +TMPDIR = /tmp + +### install directory ### + +INSTALL = /usr/bin + +### The object files (add further files here): + +OBJS = tvm2xmltv.o + +### The main target: + +all: tvm2xmltv_xsl tvm2xmltv + +### Implicit rules: + +%.o: %.cpp + $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $< + +### Dependencies: + +MAKEDEP = $(CXX) -MM -MG +DEPFILE = .dependencies +$(DEPFILE): Makefile + @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.cpp) > $@ + +-include $(DEPFILE) + +### Targets: + +tvm2xmltv_xsl: + echo -n "char xsl[]=\"" > tvm2xmltv_xsl.h + sed -e "s/\"/\\\\\"/g;" tvm2xmltv.xsl | awk '{ printf("%s",$$0); }' >> tvm2xmltv_xsl.h + echo "\";" >> tvm2xmltv_xsl.h + +tvm2xmltv: $(OBJS) + $(CXX) $(CXXFLAGS) $(OBJS) $(LIBS) -o $@ + +install: tvm2xmltv_xsl tvm2xmltv + @cp tvm2xmltv $(INSTALL) + $(STRIP) $(INSTALL)/tvm2xmltv + @mkdir -p /var/lib/epgsources + @cp tvm2xmltv.dist /var/lib/epgsources/tvm2xmltv + +dist: clean + @-rm -rf $(TMPDIR)/tvm2xmltv + @mkdir $(TMPDIR)/tvm2xmltv + @cp -a *.cpp *.h *.xsl tvm2xmltv.dist Makefile $(TMPDIR)/tvm2xmltv + @tar cfz tvm2xmltv.tgz -C $(TMPDIR) tvm2xmltv + @-rm -rf $(TMPDIR)/tvm2xmltv + +clean: + @-rm -f $(OBJS) $(DEPFILE) tvm2xmltv tvm2xmltv_xsl.h + +distclean: clean + @-rm -f *~ *.tgz diff -Nur xmltv2vdr/dist/tvm2xmltv/tvm2xmltv.cpp xmltv2vdr-n/dist/tvm2xmltv/tvm2xmltv.cpp --- xmltv2vdr/dist/tvm2xmltv/tvm2xmltv.cpp 1970-01-01 01:00:00.000000000 +0100 +++ xmltv2vdr-n/dist/tvm2xmltv/tvm2xmltv.cpp 2011-07-08 21:28:19.000000000 +0200 @@ -0,0 +1,513 @@ +/* + * tvm2xmltv.cpp: a grabber for the xmltv2vdr plugin + * + */ + +#include +#include +#include +#include +#include +#include "tvm2xmltv.h" +#include "tvm2xmltv_xsl.h" + +#include + +#define xstr(s) str(s) +#define str(s) #s + +int SysLogLevel=1; + +void syslog_with_tid(const char *format, ...) +{ + va_list ap; + char fmt[255]; + snprintf(fmt, sizeof(fmt), "tvm2xmltv: [%d] %s", getpid(), format); + va_start(ap, format); + vfprintf(stderr,fmt,ap); + va_end(ap); + fprintf(stderr,"\n"); + fflush(stderr); +} + +ctvm2xmltv::ctvm2xmltv () +{ + data.memory = NULL; + data.size = 0; + pxsltStylesheet = NULL; + sxmlDoc=NULL; +} + +ctvm2xmltv::~ctvm2xmltv () +{ + if (data.memory) + { + free (data.memory); + data.memory = NULL; + data.size = 0; + } + + if (pxsltStylesheet) + { + xsltFreeStylesheet(pxsltStylesheet); + xsltCleanupGlobals(); + xmlCleanupParser(); + } +} + +void ctvm2xmltv::LoadXSLT() +{ + if (pxsltStylesheet) return; + xmlSubstituteEntitiesDefault (1); + xmlLoadExtDtdDefaultValue = 1; + exsltRegisterAll(); + + if ((sxmlDoc = xmlReadMemory (xsl, sizeof(xsl), NULL,NULL,0)) != NULL) + { + pxsltStylesheet=xsltParseStylesheetDoc(sxmlDoc); + if (!pxsltStylesheet) + { + esyslog("can't parse stylesheet"); + xmlFreeDoc (sxmlDoc); + sxmlDoc=NULL; + } + } +} + +static size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) +{ + size_t realsize = size * nmemb; + struct MemoryStruct *mem = (struct MemoryStruct *) data; + + if (mem->memory) + mem->memory = (char *) realloc(mem->memory, mem->size + realsize + 1); + else + mem->memory = (char *) malloc(mem->size + realsize + 1); + + if (mem->memory) + { + memcpy (&(mem->memory[mem->size]), ptr, realsize); + mem->size += realsize; + mem->memory[mem->size] = 0; + } + return realsize; +} + + +int ctvm2xmltv::DownloadData(const char *url) +{ + CURL *curl_handle; + + // Initialize 'data' struct + if (data.memory) free(data.memory); + data.memory = NULL; + data.size = 0; + + int ret; + ret=curl_global_init(CURL_GLOBAL_NOTHING); + if (ret) return ret; + + curl_handle = curl_easy_init(); + if (!curl_handle) return -40; // unused curl error + curl_easy_setopt(curl_handle, CURLOPT_URL, url); // Specify URL to get + curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 0); // don't follow redirects + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); // Send all data to this function + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *) &data); // Pass our 'data' struct to the callback function + curl_easy_setopt(curl_handle, CURLOPT_MAXFILESIZE, 1048576); // Set maximum file size to get (bytes) + curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1); // No progress meter + curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1); // No signaling + curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 30); // Set timeout to 30 seconds + curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, TVM2XMLTV_USERAGENT); // Some servers don't like requests that are made without a user-agent field + + ret=curl_easy_perform(curl_handle); + if (ret) + { + if (data.memory) + { + free(data.memory); + data.memory = NULL; + } + data.size = 0; + } + else + { + long code; + curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &code); + if (code==407) + { + if (data.memory) + { + free(data.memory); + data.memory=NULL; + } + data.size=0; + ret=10; + } + else + if (code!=200) + { + if (data.memory) + { + free(data.memory); + data.memory = NULL; + + } + data.size = 0; + ret=22; + } + } + + if ((data.size<120) && (!ret)) + { + // empty xml -> prevent processing + if (data.memory) + { + free(data.memory); + data.memory = NULL; + + } + data.size = 0; + ret=22; + } + + curl_easy_cleanup(curl_handle); // Cleanup curl stuff + curl_global_cleanup(); + return (data.size!=0) ? (int) data.size : -ret; +} + +void ctvm2xmltv::Unscramble() +{ + char buffer[1000]; + int pos = 0; + + if (data.size<2) return; + if ((data.memory[0]==31) && (data.memory[1]==-117)) return; // already gz format + + struct + { + int offset; + int len; + } hunktab[] = + {{0x006a,6},{0x0064,6},{0x0070,88},{0x0320,17},{0x0011,83},{0x012c,100}, + {0x0000,17},{0x0331,183},{0x0258,200},{0x0190,200},{0x00c8,100} + }; + + for (size_t i = 0; i < (sizeof (hunktab) / sizeof (hunktab[0])); i++) + { + memcpy(&buffer[pos], &data.memory[hunktab[i].offset], hunktab[i].len); + pos += hunktab[i].len; + } + + memcpy(data.memory, buffer, sizeof (buffer)); +} + +bool ctvm2xmltv::Uncompress() +{ + int len; + memcpy(&len,data.memory+data.size-4,4); + if (len>1048576) return false; + char *buf=(char *) malloc(len+10); + if (!buf) return false; + + z_stream zstrm; + memset(&zstrm,0,sizeof(z_stream)); + + zstrm.next_in=(Bytef*)data.memory; + zstrm.avail_in=data.size; + zstrm.next_out=(Bytef*)buf; + zstrm.avail_out=len; + zstrm.data_type=Z_TEXT; + + if (inflateInit2(&zstrm,15+32)!=Z_OK) + { + free(buf); + return false; + } + + bool done=false; + int ret; + while (!done) + { + ret=inflate(&zstrm,Z_SYNC_FLUSH); + if (ret==Z_STREAM_END) done=true; + else if (ret!=Z_OK) break; + } + if (inflateEnd(&zstrm) != Z_OK) + { + free(buf); + return false; + } + + free(data.memory); + data.memory=buf; + data.size=len; + + return true; +} + +int ctvm2xmltv::Fetch(const char *channel,int days, int num, bool cut) +{ + for (int day=0; day<=days; day++) + { + time_t clock = time (NULL)+(day*86400); + struct tm tm; + localtime_r(&clock, &tm); + + char *url = NULL; + char *filename = NULL; + if (asprintf (&filename, "%4d%02d%02d_%03d.xml", tm.tm_year + 1900, + tm.tm_mon + 1, tm.tm_mday, num) == -1) + { + esyslog("failed to allocate string"); + return 1; + } + if (asprintf (&url, TVM2XMLTV_URL, filename) == -1) + { + esyslog("failed to allocate string"); + free(filename); + return 1; + } + if (filename) free(filename); + + int ret=DownloadData(url); + free (url); + // -40 fatal curl error + // -10 wrong proxy auth + // -7 couldn't connect + // -6 couldn't resolve host (proxy) + // -22 not found + if (ret==-40) + { + esyslog("fatal curl error"); + return 1; + } + if (ret==-10) + { + esyslog("wrong proxy auth"); + return 1; + } + if (ret==-7) + { + esyslog("failed to connect"); + return 2; + } + if (ret==-6) + { + esyslog("failed to resolve host"); + return 2; + } + if (ret==-22) + { + /* channel doesnt exists any more? -> clear from list! */ + esyslog("channel %i doesn't exist", num); + return 1; + + } + if (ret>0) + { + Unscramble(); + if (!Uncompress()) + { + esyslog("failed uncompressing buffer"); + return 1; + } + const char *params[3] = + { + "channelid", channel, NULL + }; + if (!Translate(params,cut)) + { + return 1; + } + } + } + return 0; +} + +int ctvm2xmltv::Process(int argc, char *argv[]) +{ + FILE *f=fopen("/var/lib/epgsources/tvm2xmltv","r"); + if (!f) + { + esyslog("failed to open tvm2xmltv config"); + return 1; + } + char *line=NULL,*lptr=NULL; + size_t size; + getline(&line,&size,f); + getline(&line,&size,f); + char *sc=strchr(line,';'); + if (sc) + { + *sc=0; + sc++; + } + else + { + sc=line; + } + int daysmax=atoi(sc); + if (daysmax<0) daysmax=1; + int daysinadvance=atoi(argv[1]); + if (daysinadvance<0) daysinadvance=1; + if (daysinadvance>daysmax) daysinadvance=15; + + bool head=false; + if (!line) + { + line=(char *) malloc(81); + size=80; + } + for (;;) + { + lptr=line+1; + line[0]=' '; + if (getline(&lptr,&size,f)==-1) break; + char *channel=line; + char *sc=strchr(channel,';'); + if (sc) *sc=0; + + bool use=false; + for (int i=3; i\n"); + printf("\n"); + head=true; + } + printf("\n",lptr); + printf("%s\n",lptr); + printf("\n"); + break; + } + } + + if (use) + { + int num=atoi(sc+1); + if (num>0) + { + channel[0]='"'; + *sc++='"'; + char *cl=strchr(sc,':'); + int num2=0; + if (cl) + { + cl++; + num2=atoi(cl); + } + *sc=0; + int ret=0; + if ((ret=Fetch(channel,daysinadvance,num,(num2!=0)))!=0) + { + if (line) free(line); + fclose(f); + return ret; + } + if (num2) + { + if ((ret=Fetch(channel,daysinadvance,num2,true))!=0) + { + if (line) free(line); + fclose(f); + return ret; + } + } + } + } + } + if (line) free(line); + fclose(f); + if (head) printf(""); + return 0; +} + +void ctvm2xmltv::CutCloseDown(xmlDocPtr doc) +{ + xmlNodePtr delnode=NULL; + xmlNodePtr node=doc->children; + while (node) + { + if (node->type==XML_ELEMENT_NODE) + { + if ((!xmlStrcasecmp(node->name, (const xmlChar *) "programme"))) + { + xmlNodePtr cnode=node->xmlChildrenNode; + while (cnode) + { + if (cnode->type==XML_ELEMENT_NODE) + { + if ((!xmlStrcasecmp(cnode->name, (const xmlChar *) "title"))) + { + xmlChar *content=xmlNodeListGetString(cnode->doc,cnode->xmlChildrenNode,1); + if (content) + { + if ((!xmlStrcasecmp(content, (const xmlChar *) "sendepause"))) + { + delnode=node; + } + xmlFree(content); + } + } + } + if (delnode) break; + cnode=cnode->next; + } + + } + } + if (delnode) break; + node=node->next; + } + if (delnode) xmlUnlinkNode(delnode); +} + +bool ctvm2xmltv::Translate(const char **params, bool cutclosedown) +{ + int fd; + fd=open("/tmp/data.xml",O_CREAT|O_TRUNC|O_RDWR,0644); + if (fd!=-1) write(fd,data.memory,data.size); + close(fd); + + + xmlDocPtr pxmlDoc; + if (!pxsltStylesheet) LoadXSLT(); + if ((pxmlDoc = xmlReadMemory (data.memory, data.size, NULL,NULL,0)) != NULL) + { + xmlDocPtr res=NULL; + if ((res = xsltApplyStylesheet (pxsltStylesheet, pxmlDoc, (const char **)params)) == NULL) + { + dsyslog("error applying xslt stylesheet"); + return false; + } + else + { + if (cutclosedown) CutCloseDown(res); + + xsltSaveResultToFile(stdout,res,pxsltStylesheet); + xmlFreeDoc (res); + } + xmlFreeDoc (pxmlDoc); + } + else + { + esyslog("error parsing xml file"); + return false; + } + + return true; +} + +int main(int argc, char *argv[]) +{ + if (argc<4) return 132; + ctvm2xmltv *tvm2xmltv = new ctvm2xmltv; + int ret=tvm2xmltv->Process(argc,argv); + delete tvm2xmltv; + return ret; +} + diff -Nur xmltv2vdr/dist/tvm2xmltv/tvm2xmltv.h xmltv2vdr-n/dist/tvm2xmltv/tvm2xmltv.h --- xmltv2vdr/dist/tvm2xmltv/tvm2xmltv.h 1970-01-01 01:00:00.000000000 +0100 +++ xmltv2vdr-n/dist/tvm2xmltv/tvm2xmltv.h 2012-09-03 16:08:34.000000000 +0200 @@ -0,0 +1,54 @@ +/* + * tvm2xmltv.h: a grabber for the xmltv2vdr plugin + * + */ + +#ifndef __TVM2XMLTV_H +#define __TVM2XMLTV_H + +#include +// #include +#include + +#include +#include +#include + +#include +#include +#include + +#define esyslog(a...) void( (SysLogLevel > 0) ? syslog_with_tid(a) : void() ) +#define isyslog(a...) void( (SysLogLevel > 1) ? syslog_with_tid(a) : void() ) +#define dsyslog(a...) void( (SysLogLevel > 2) ? syslog_with_tid(a) : void() ) +#define tsyslog(a...) void( (SysLogLevel > 3) ? syslog_with_tid(a) : void() ) + +#define TVM2XMLTV_USERAGENT "libcurl-agent/1.0" +#define TVM2XMLTV_URL "http://wwwa.tvmovie.de/static/tvghost/html/onlinedata/xml-gz5/%s.tvm" + +struct MemoryStruct +{ + char *memory; + size_t size; +}; + +class ctvm2xmltv +{ +private: + struct MemoryStruct data; + xsltStylesheetPtr pxsltStylesheet; + xmlDocPtr sxmlDoc; + void CutCloseDown(xmlDocPtr doc); + int Fetch(const char *channel,int days, int num, bool cut); + int DownloadData(const char *url); + void Unscramble(); + bool Uncompress(); + bool Translate(const char **params, bool cutclosedown=false); + void LoadXSLT(); +public: + ctvm2xmltv(); + ~ctvm2xmltv(); + int Process(int argc, char *argv[]); +}; + +#endif //__TVM2XMLTV_H