diff options
author | Christian Wieninger <winni@debian.(none)> | 2007-11-11 15:40:28 +0100 |
---|---|---|
committer | Christian Wieninger <winni@debian.(none)> | 2007-11-11 15:40:28 +0100 |
commit | 8d4f8607dc1558ce73eb4c376bdbf78ddb65da83 (patch) | |
tree | d0c5dde81a36ab2e8a2edc7c1e6922556518b312 /blacklist.c | |
download | vdr-plugin-epgsearch-8d4f8607dc1558ce73eb4c376bdbf78ddb65da83.tar.gz vdr-plugin-epgsearch-8d4f8607dc1558ce73eb4c376bdbf78ddb65da83.tar.bz2 |
Initial commit
Diffstat (limited to 'blacklist.c')
-rw-r--r-- | blacklist.c | 762 |
1 files changed, 762 insertions, 0 deletions
diff --git a/blacklist.c b/blacklist.c new file mode 100644 index 0000000..aff3211 --- /dev/null +++ b/blacklist.c @@ -0,0 +1,762 @@ +/* +Copyright (C) 2004-2007 Christian Wieninger + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + +The author can be reached at cwieninger@gmx.de + +The project's page is at http://winni.vdr-developer.org/epgsearch +*/ + +#include <vector> +#include "epgsearchtools.h" +#include "blacklist.h" +#include "epgsearchcats.h" +#include <vdr/tools.h> +#include "menu_dirselect.h" +#include "changrp.h" +#include "menu_search.h" +#include "menu_searchedit.h" +#include "menu_searchresults.h" +#include <math.h> +#ifdef HAVE_PCREPOSIX +#include <pcreposix.h> +#else +#include <regex.h> +#endif + +cBlacklists Blacklists; + +// -- cBlacklist ----------------------------------------------------------------- +char *cBlacklist::buffer = NULL; + +cBlacklist::cBlacklist(void) +{ + ID = -1; + *search = 0; + options = 1; + useTime = false; + startTime = 0000; + stopTime = 2359; + useChannel = false; + channelMin = Channels.GetByNumber(cDevice::CurrentChannel()); + channelMax = Channels.GetByNumber(cDevice::CurrentChannel()); + channelGroup = NULL; + useCase = false; + mode = 0; + useTitle = true; + useSubtitle = true; + useDescription = true; + useDuration = false; + minDuration = 0; + maxDuration = 130; + useDayOfWeek = false; + DayOfWeek = 0; + buffer = NULL; + + useExtEPGInfo = false; + catvalues = (char**) malloc(SearchExtCats.Count() * sizeof(char*)); + cSearchExtCat *SearchExtCat = SearchExtCats.First(); + int index = 0; + while (SearchExtCat) + { + catvalues[index] = (char*)malloc(MaxFileName); + *catvalues[index] = 0; + SearchExtCat = SearchExtCats.Next(SearchExtCat); + index++; + } + ignoreMissingEPGCats = 0; + fuzzyTolerance = 1; +} + +cBlacklist::~cBlacklist(void) +{ + if (buffer) { + free(buffer); + buffer = NULL; + } + if (catvalues) + { + cSearchExtCat *SearchExtCat = SearchExtCats.First(); + int index = 0; + while (SearchExtCat) + { + free(catvalues[index]); + SearchExtCat = SearchExtCats.Next(SearchExtCat); + index++; + } + free(catvalues); + catvalues = NULL; + } +} + +cBlacklist& cBlacklist::operator= (const cBlacklist &Blacklist) +{ + memcpy(this, &Blacklist, sizeof(*this)); + catvalues = (char**) malloc(SearchExtCats.Count() * sizeof(char*)); + cSearchExtCat *SearchExtCat = SearchExtCats.First(); + int index = 0; + while (SearchExtCat) + { + catvalues[index] = (char*)malloc(MaxFileName); + *catvalues[index] = 0; + strcpy(catvalues[index], Blacklist.catvalues[index]); + SearchExtCat = SearchExtCats.Next(SearchExtCat); + index++; + } + return *this; +} + +void cBlacklist::CopyFromTemplate(const cSearchExt* templ) +{ + options = templ->options; + useTime = templ->useTime; + startTime = templ->startTime; + stopTime = templ->stopTime; + useChannel = templ->useChannel; + useCase = templ->useCase; + mode = templ->mode; + useTitle = templ->useTitle; + useSubtitle = templ->useSubtitle; + useDescription = templ->useDescription; + useDuration = templ->useDuration; + minDuration = templ->minDuration; + maxDuration = templ->maxDuration; + useDayOfWeek = templ->useDayOfWeek; + DayOfWeek = templ->DayOfWeek; + useExtEPGInfo = templ->useExtEPGInfo; + + cSearchExtCat *SearchExtCat = SearchExtCats.First(); + int index = 0; + while (SearchExtCat) + { + strcpy(catvalues[index], templ->catvalues[index]); + SearchExtCat = SearchExtCats.Next(SearchExtCat); + index++; + } + + channelMin = templ->channelMin; + channelMax = templ->channelMax; + if (channelGroup) + free(channelGroup); + if (templ->channelGroup) + channelGroup = strdup(templ->channelGroup); + fuzzyTolerance = templ->fuzzyTolerance; + ignoreMissingEPGCats = templ->ignoreMissingEPGCats; +} + +bool cBlacklist::operator< (const cListObject &ListObject) +{ + cBlacklist *BL = (cBlacklist *)&ListObject; + return strcasecmp(search, BL->search) < 0; +} + +const char *cBlacklist::ToText(void) +{ + char tmp_Start[5] = ""; + char tmp_Stop[5] = ""; + char tmp_minDuration[5] = ""; + char tmp_maxDuration[5] = ""; + char* tmp_chanSel = NULL; + char* tmp_search = NULL; + char* tmp_catvalues = NULL; + + free(buffer); + if (mode < 4 || mode == 5) // not a regular expression + asprintf(&tmp_search, "%s", search); + else if (mode ==4) + { + tmp_search = strdup(search); + while(strstr(tmp_search, "|")) + tmp_search = strreplace(tmp_search, "|", "!^pipe^!"); // ugly: replace with something, that should not happen to be part of a regular expression + } + strreplace(tmp_search, ':', '|'); + + if (useTime) + { + sprintf(tmp_Start, "%04d", startTime); + sprintf(tmp_Stop, "%04d", stopTime); + } + if (useDuration) + { + sprintf(tmp_minDuration, "%04d", minDuration); + sprintf(tmp_maxDuration, "%04d", maxDuration); + } + + if (useChannel==1) + { + if (channelMin->Number() < channelMax->Number()) + asprintf(&tmp_chanSel, "%s|%s", CHANNELSTRING(channelMin), CHANNELSTRING(channelMax)); + else + asprintf(&tmp_chanSel, "%s", CHANNELSTRING(channelMin)); + } + if (useChannel==2) + { + int channelGroupNr = ChannelGroups.GetIndex(channelGroup); + if (channelGroupNr == -1) + { + LogFile.eSysLog("channel group %s does not exist!", channelGroup); + useChannel = 0; + } + else + tmp_chanSel = strdup(channelGroup); + } + + if (useExtEPGInfo) + { + cSearchExtCat *SearchExtCat = SearchExtCats.First(); + int index = 0; + while (SearchExtCat) + { + char* catvalue = NULL; + asprintf(&catvalue, "%s", catvalues[index]); + while(strstr(catvalue, ":")) + catvalue = strreplace(catvalue, ":", "!^colon^!"); // ugly: replace with something, that should not happen to be part ofa category value + while(strstr(catvalue, "|")) + catvalue = strreplace(catvalue, "|", "!^pipe^!"); // ugly: replace with something, that should not happen to be part of a regular expression + + if (index == 0) + asprintf(&tmp_catvalues, "%d#%s", SearchExtCat->id, catvalue); + else + { + char* temp = tmp_catvalues; + asprintf(&tmp_catvalues, "%s|%d#%s", tmp_catvalues, SearchExtCat->id, catvalue); + free(temp); + } + SearchExtCat = SearchExtCats.Next(SearchExtCat); + index++; + free(catvalue); + } + } + + asprintf(&buffer, "%d:%s:%d:%s:%s:%d:%s:%d:%d:%d:%d:%d:%d:%s:%s:%d:%d:%d:%s:%d:%d", + ID, + tmp_search, + useTime, + tmp_Start, + tmp_Stop, + useChannel, + (useChannel>0 && useChannel<3)?tmp_chanSel:"0", + useCase, + mode, + useTitle, + useSubtitle, + useDescription, + useDuration, + tmp_minDuration, + tmp_maxDuration, + useDayOfWeek, + DayOfWeek, + useExtEPGInfo, + useExtEPGInfo?tmp_catvalues:"", + fuzzyTolerance, + ignoreMissingEPGCats); + + + if (tmp_chanSel) + free(tmp_chanSel); + if (tmp_search) + free(tmp_search); + if (tmp_catvalues) + free(tmp_catvalues); + + + return buffer; +} + +bool cBlacklist::Parse(const char *s) +{ + char *line; + char *pos; + char *pos_next; + int parameter = 1; + int valuelen; + char value[MaxFileName]; + + pos = line = strdup(s); + pos_next = pos + strlen(pos); + if (*pos_next == '\n') *pos_next = 0; + while (*pos) { + while (*pos == ' ') pos++; + if (*pos) { + if (*pos != ':') { + pos_next = strchr(pos, ':'); + if (!pos_next) + pos_next = pos + strlen(pos); + valuelen = pos_next - pos + 1; + if (valuelen > MaxFileName) valuelen = MaxFileName; + strn0cpy(value, pos, valuelen); + pos = pos_next; + switch (parameter) { + case 1: ID = atoi(value); + break; + case 2: strcpy(search, value); + break; + case 3: useTime = atoi(value); + break; + case 4: startTime = atoi(value); + break; + case 5: stopTime = atoi(value); + break; + case 6: useChannel = atoi(value); + break; + case 7: + if (useChannel == 0) + { + channelMin = NULL; + channelMax = NULL; + } + else if (useChannel == 1) + { + int minNum=0, maxNum=0; + int fields = sscanf(value, "%d-%d", &minNum, &maxNum); + if (fields == 0) // stored with ID + { + char *channelMinbuffer = NULL; + char *channelMaxbuffer = NULL; + int channels = sscanf(value, "%a[^|]|%a[^|]", &channelMinbuffer, &channelMaxbuffer); + channelMin = Channels.GetByChannelID(tChannelID::FromString(channelMinbuffer), true, true); + if (!channelMin) + { + LogFile.eSysLog("ERROR: channel %s not defined", channelMinbuffer); + channelMin = channelMax = NULL; + useChannel = 0; + } + if (channels == 1) + channelMax = channelMin; + else + { + channelMax = Channels.GetByChannelID(tChannelID::FromString(channelMaxbuffer), true, true); + if (!channelMax) + { + LogFile.eSysLog("ERROR: channel %s not defined", channelMaxbuffer); + channelMin = channelMax = NULL; + useChannel = 0; + } + } + free(channelMinbuffer); + free(channelMaxbuffer); + } + } + else if (useChannel == 2) + channelGroup = strdup(value); + break; + case 8: useCase = atoi(value); + break; + case 9: mode = atoi(value); + break; + case 10: useTitle = atoi(value); + break; + case 11: useSubtitle = atoi(value); + break; + case 12: useDescription = atoi(value); + break; + case 13: useDuration = atoi(value); + break; + case 14: minDuration = atoi(value); + break; + case 15: maxDuration = atoi(value); + break; + case 16: useDayOfWeek = atoi(value); + break; + case 17: DayOfWeek = atoi(value); + break; + case 18: useExtEPGInfo = atoi(value); + break; + case 19: + if (!ParseExtEPGValues(value)) + { + LogFile.eSysLog("ERROR reading ext. EPG values - 1"); + free(line); + return false; + } + break; + case 20: fuzzyTolerance = atoi(value); + break; + case 21: ignoreMissingEPGCats = atoi(value); + break; + } //switch + } + parameter++; + } + if (*pos) pos++; + } //while + + strreplace(search, '|', ':'); + while(strstr(search, "!^pipe^!")) + strreplace(search, "!^pipe^!", "|"); + + free(line); + return (parameter >= 19) ? true : false; +} + +bool cBlacklist::ParseExtEPGValues(const char *s) +{ + char *line; + char *pos; + char *pos_next; + int valuelen; + char value[MaxFileName]; + + pos = line = strdup(s); + pos_next = pos + strlen(pos); + if (*pos_next == '\n') *pos_next = 0; + while (*pos) { + while (*pos == ' ') pos++; + if (*pos) { + if (*pos != '|') { + pos_next = strchr(pos, '|'); + if (!pos_next) + pos_next = pos + strlen(pos); + valuelen = pos_next - pos + 1; + if (valuelen > MaxFileName) valuelen = MaxFileName; + strn0cpy(value, pos, valuelen); + pos = pos_next; + if (!ParseExtEPGEntry(value)) + { + LogFile.eSysLog("ERROR reading ext. EPG value: %s", value); + free(line); + return false; + } + } + } + if (*pos) pos++; + } //while + + free(line); + return true; +} + +bool cBlacklist::ParseExtEPGEntry(const char *s) +{ + char *line; + char *pos; + char *pos_next; + int parameter = 1; + int valuelen; + char value[MaxFileName]; + int currentid = -1; + + pos = line = strdup(s); + pos_next = pos + strlen(pos); + if (*pos_next == '\n') *pos_next = 0; + while (*pos) { + while (*pos == ' ') pos++; + if (*pos) { + if (*pos != '#') { + pos_next = strchr(pos, '#'); + if (!pos_next) + pos_next = pos + strlen(pos); + valuelen = pos_next - pos + 1; + if (valuelen > MaxFileName) valuelen = MaxFileName; + strn0cpy(value, pos, valuelen); + pos = pos_next; + switch (parameter) { + case 1: + { + currentid = atoi(value); + int index = SearchExtCats.GetIndexFromID(currentid); + if (index > -1) + strcpy(catvalues[index], ""); + } + break; + case 2: + if (currentid > -1) + { + int index = SearchExtCats.GetIndexFromID(currentid); + if (index > -1) + { + while(strstr(value, "!^colon^!")) + strreplace(value, "!^colon^!", ":"); + while(strstr(value, "!^pipe^!")) + strreplace(value, "!^pipe^!", "|"); + strcpy(catvalues[index], value); + } + } + break; + } //switch + } + parameter++; + } + if (*pos) pos++; + } //while + + free(line); + return (parameter >= 2) ? true : false; +} + +bool cBlacklist::Save(FILE *f) +{ + return fprintf(f, "%s\n", ToText()) > 0; +} + +cEvent * cBlacklist::GetEventByBlacklist(const cSchedule *schedules, const cEvent *Start, int MarginStop) +{ + cEvent *pe = NULL; + cEvent *p1 = NULL; + + if (Start) + p1 = schedules->Events()->Next(Start); + else + p1 = schedules->Events()->First(); + + time_t tNow=time(NULL); + char* szTest = NULL; + char* searchText = strdup(search); + + if (!useCase) + ToLower(searchText); + + int searchStart = 0, searchStop = 0; + if (useTime) + { + searchStart = startTime; + searchStop = stopTime; + if (searchStop < searchStart) + searchStop += 2400; + } + int minSearchDuration = 0; + int maxSearchDuration = 0; + if (useDuration) + { + minSearchDuration = minDuration/100*60 + minDuration%100; + maxSearchDuration = maxDuration/100*60 + maxDuration%100; + } + + for (cEvent *p = p1; p; p = schedules->Events()->Next(p)) + { + if(!p) + { + break; + } + + if (szTest) + { + free(szTest); + szTest = NULL; + } + + // ignore events without title + if (!p->Title() || strlen(p->Title()) == 0) + continue; + + asprintf(&szTest, "%s%s%s%s%s", (useTitle?p->Title():""), (useSubtitle||useDescription)?"~":"", + (useSubtitle?p->ShortText():""),useDescription?"~":"", + (useDescription?p->Description():"")); + + if (tNow < p->EndTime() + MarginStop * 60) + { + if (!useCase) + ToLower(szTest); + + if (useTime) + { + time_t tEvent = p->StartTime(); + struct tm tmEvent; + localtime_r(&tEvent, &tmEvent); + int eventStart = tmEvent.tm_hour*100 + tmEvent.tm_min; + int eventStart2 = tmEvent.tm_hour*100 + tmEvent.tm_min + 2400; + if ((eventStart < searchStart || eventStart > searchStop) && + (eventStart2 < searchStart || eventStart2 > searchStop)) + continue; + } + if (useDuration) + { + int duration = p->Duration()/60; + if (minSearchDuration > duration || maxSearchDuration < duration) + continue; + } + + if (useDayOfWeek) + { + time_t tEvent = p->StartTime(); + struct tm tmEvent; + localtime_r(&tEvent, &tmEvent); + if (DayOfWeek >= 0 && DayOfWeek != tmEvent.tm_wday) + continue; + if (DayOfWeek < 0) + { + int iFound = 0; + for(int i=0; i<7; i++) + if (abs(DayOfWeek) & (int)pow(2,i) && i == tmEvent.tm_wday) + { + iFound = 1; + break; + } + if (!iFound) + continue; + } + } + + if (strlen(szTest) > 0) + { + if (!MatchesSearchMode(szTest, searchText, mode," ,;|~", fuzzyTolerance)) + continue; + } + + if (useExtEPGInfo && !MatchesExtEPGInfo(p)) + continue; + pe=p; + break; + } + } + if (szTest) + free(szTest); + free(searchText); + return pe; +} + +// returns a pointer array to the matching search results +cSearchResults* cBlacklist::Run(cSearchResults* pSearchResults, int MarginStop) +{ + LogFile.Log(3,"start search for blacklist '%s'", search); + + cSchedulesLock schedulesLock; + const cSchedules *schedules; + schedules = cSchedules::Schedules(schedulesLock); + if(!schedules) { + LogFile.Log(1,"schedules are currently locked! try again later."); + return NULL; + } + + const cSchedule *Schedule = schedules->First(); + + while (Schedule) { + cChannel* channel = Channels.GetByChannelID(Schedule->ChannelID(),true,true); + if (!channel) + { + Schedule = (const cSchedule *)schedules->Next(Schedule); + continue; + } + + if (useChannel == 1 && channelMin && channelMax) + { + if (channelMin->Number() > channel->Number() || channelMax->Number() < channel->Number()) + { + Schedule = (const cSchedule *)schedules->Next(Schedule); + continue; + } + } + if (useChannel == 2 && channelGroup) + { + cChannelGroup* group = ChannelGroups.GetGroupByName(channelGroup); + if (!group || !group->ChannelInGroup(channel)) + { + Schedule = (const cSchedule *)schedules->Next(Schedule); + continue; + } + } + + if (useChannel == 3) + { + if (channel->Ca() >= CA_ENCRYPTED_MIN) + { + Schedule = (const cSchedule *)schedules->Next(Schedule); + continue; + } + } + + const cEvent *pPrevEvent = NULL; + do { + const cEvent* event = GetEventByBlacklist(Schedule, pPrevEvent, MarginStop); + pPrevEvent = event; + if (event && Channels.GetByChannelID(event->ChannelID(),true,true)) + { + if (!pSearchResults) pSearchResults = new cSearchResults; + pSearchResults->Add(new cSearchResult(event, this)); + } + } while(pPrevEvent); + Schedule = (const cSchedule *)schedules->Next(Schedule); + } + LogFile.Log(3,"found %d event(s) for blacklist '%s'", pSearchResults?pSearchResults->Count():0, search); + + return pSearchResults; +} + +bool cBlacklist::MatchesExtEPGInfo(const cEvent* e) +{ + if (!e || !e->Description()) + return false; + cSearchExtCat* SearchExtCat = SearchExtCats.First(); + while (SearchExtCat) + { + char* value = NULL; + int index = SearchExtCats.GetIndexFromID(SearchExtCat->id); + if (index > -1) + value = catvalues[index]; + if (value && strlen(value) > 0) + { + char* testvalue = GetExtEPGValue(e, SearchExtCat); + if (!testvalue) + return false; + + // compare not case sensitive + char* valueLower = strdup(value); + ToLower(valueLower); + ToLower(testvalue); + if (!MatchesSearchMode(testvalue, valueLower, SearchExtCat->searchmode, ",;|~", fuzzyTolerance)) + { + free(testvalue); + free(valueLower); + return false; + } + free(testvalue); + free(valueLower); + } + SearchExtCat = SearchExtCats.Next(SearchExtCat); + } + return true; +} + +// -- cBlacklists ---------------------------------------------------------------- +int cBlacklists::GetNewID() +{ + int newID = -1; + cMutexLock BlacklistLock(this); + cBlacklist *l = (cBlacklist *)First(); + while (l) { + newID = max(newID, l->ID); + l = (cBlacklist *)l->Next(); + } + return newID+1; +} + +cBlacklist* cBlacklists::GetBlacklistFromID(int ID) +{ + if (ID == -1) + return NULL; + cMutexLock BlacklistLock(this); + cBlacklist *l = (cBlacklist *)First(); + while (l) { + if (l->ID == ID) + return l; + l = (cBlacklist *)l->Next(); + } + return NULL; +} + +bool cBlacklists::Exists(const cBlacklist* Blacklist) +{ + cMutexLock BlacklistLock(this); + cBlacklist *l = (cBlacklist*)First(); + while (l) + { + if (l == Blacklist) + return true; + l = (cBlacklist*)l->Next(); + } + return false; +} |