diff options
Diffstat (limited to 'vdr-vdrmanager/helpers.cpp')
-rw-r--r-- | vdr-vdrmanager/helpers.cpp | 467 |
1 files changed, 467 insertions, 0 deletions
diff --git a/vdr-vdrmanager/helpers.cpp b/vdr-vdrmanager/helpers.cpp new file mode 100644 index 0000000..4944614 --- /dev/null +++ b/vdr-vdrmanager/helpers.cpp @@ -0,0 +1,467 @@ +/* + * event und message handler + */ + +#include <time.h> +#include <unistd.h> +#include <values.h> +#include <vdr/plugin.h> +#include <vdr/timers.h> +#include <vdr/channels.h> +#include <vdr/epg.h> +#include <vdr/videodir.h> +#include "helpers.h" +#include "vdrmanagerthread.h" + +string cHelpers::GetTimers(string args) { + return SafeCall(GetTimersIntern); +} + +string cHelpers::GetChannels(string args) { + return SafeCall(GetChannelsIntern, args); +} + +string cHelpers::GetChannelEvents(string args) { + return SafeCall(GetEventsIntern, Trim(args), ""); +} + +string cHelpers::GetTimeEvents(string args) { + + args = Trim(args); + + size_t space = args.find(' '); + if (space == string::npos) { + return SafeCall(GetEventsIntern, "", args); + } + + string when = args.substr(0, space); + string wantedChannels = args.substr(space+1); + + return SafeCall(GetEventsIntern, Trim(wantedChannels), Trim(when)); +} + +string cHelpers::SetTimer(string args) { + return SafeCall(SetTimerIntern, args); +} + +string cHelpers::SearchEvents(string args) { + + args = Trim(args); + + size_t space = args.find(' '); + if (space == string::npos) { + return "!ERROR\r\n"; + } + + string wantedChannels = args.substr(0, space); + string pattern = args.substr(space+1); + + return SafeCall(SearchEventsIntern, Trim(wantedChannels), Trim(pattern)); + +} + +string cHelpers::GetTimersIntern() { + + string result = "START\r\n"; + + // iterate through all timers + for(cTimer * timer = Timers.First(); timer; timer = Timers.Next(timer)) { + result += ToText(timer); + } + + return result + "END\r\n"; +} + +string cHelpers::GetChannelsIntern(string wantedChannels) { + + string result = "START\r\n"; + string currentGroup = ""; + + char number[10]; + for(cChannel * channel = Channels.First(); channel; channel = Channels.Next(channel)) { + + // channel group + if (channel->GroupSep()) { + currentGroup = channel->Name(); + continue; + } + + // channel filtering + if (IsWantedChannel(channel, wantedChannels)) { + // current group + if (currentGroup.length() > 0) { + result += "C0:"; + result += currentGroup; + result += "\r\n"; + currentGroup = ""; + } + + // channel + sprintf(number, "C%d", channel->Number()); + result += number; + result += ":"; + result += channel->Name(); + result += "\r\n"; + } + } + + return result + "END\r\n"; +} + +string cHelpers::GetEventsIntern(string wantedChannels, string when) { + + when = ToUpper(when); + time_t wantedTime; + if (when == "NOW" || when == "NEXT") { + wantedTime = time(0); + } else { + wantedTime = atol(when.c_str()); + } + + string result = "START\r\n"; + + cSchedulesLock schedulesLock; + const cSchedules * schedules = cSchedules::Schedules(schedulesLock); + for(cSchedule * schedule = schedules->First(); schedule; schedule = schedules->Next(schedule)) { + + cChannel * channel = Channels.GetByChannelID(schedule->ChannelID()); + if (!IsWantedChannel(channel, wantedChannels)) { + continue; + } + + const cList<cEvent> * events = schedule->Events(); + for(cEvent * event = events->First(); event; event = events->Next(event)) { + if (IsWantedTime(wantedTime, event)) { + cEvent * match = event; + if (when == "NEXT") { + match = events->Next(match); + if (!match) { + break; + } + } + + result += ToText(match); + + if (when.length() > 0) { + break; + } + } + } + } + + return result + "END\r\n"; +} + +string cHelpers::SetTimerIntern(string args) { + + // separete timer number + size_t sep = args.find(':'); + if (sep == string::npos) { + return "!ERROR\r\n"; + } + int number = atoi(args.c_str()); + bool delTimer = number < 0; + if (delTimer) { + number = -number; + } + string params = args.substr(sep+1); + + // parse timer + cTimer * timer = new cTimer; + if (!timer->Parse(params.c_str())) { + delete timer; + return "!ERROR\r\n"; + } + + if (!number) { + // new timer + Timers.Add(timer); + } else { + // modify timer + delete timer; + cTimer * oldTimer = Timers.Get(number); + if (!oldTimer) { + return "!ERROR\r\n"; + } + if (delTimer) { + Timers.Del(oldTimer, true); + } else { + oldTimer->Parse(params.c_str()); + } + } + Timers.Save(); + + return "START\r\nEND\r\n"; +} + + +string cHelpers::SearchEventsIntern(string wantedChannels, string pattern) { + + string result = "START\r\n"; + + cSchedulesLock schedulesLock; + const cSchedules * schedules = cSchedules::Schedules(schedulesLock); + for(cSchedule * schedule = schedules->First(); schedule; schedule = schedules->Next(schedule)) { + + cChannel * channel = Channels.GetByChannelID(schedule->ChannelID()); + if (!IsWantedChannel(channel, wantedChannels)) { + continue; + } + + const cList<cEvent> * events = schedule->Events(); + for(cEvent * event = events->First(); event; event = events->Next(event)) { + + if (IsWantedEvent(event, pattern)) { + result += ToText(event); + } + } + } + + return result + "END\r\n"; +} + +string cHelpers::ToText(cTimer * timer) { + + const char * channelName = timer->Channel()->Name(); + + string result; + char buf[100]; + sprintf(buf, "T%d", timer->Index()); + result = buf; + result += ":"; + sprintf(buf, "%u", timer->Flags()); + result += buf; + result += ":"; + sprintf(buf, "%d", timer->Channel()->Number()); + result += buf; + result += ":"; + result += channelName; + result += ":"; + sprintf(buf, "%lu", timer->StartTime()); + result += buf; + result += ":"; + sprintf(buf, "%lu", timer->StopTime()); + result += buf; + result += ":"; + sprintf(buf, "%d", timer->Priority()); + result += buf; + result += ":"; + sprintf(buf, "%d", timer->Lifetime()); + result += buf; + result += ":"; + result += MapSpecialChars(timer->File()); + result += ":"; + result += MapSpecialChars(timer->Aux() ? timer->Aux() : ""); + result += "\r\n"; + + return result; +} + +string cHelpers::ToText(cEvent * event) { + + + cChannel * channel = Channels.GetByChannelID(event->Schedule()->ChannelID()); + + // search assigned timer + cTimer * eventTimer = NULL; + for(cTimer * timer = Timers.First(); timer; timer = Timers.Next(timer)) { + if (timer->Channel() == channel && timer->StartTime() <= event->StartTime() && + timer->StopTime() >= event->StartTime() + event->Duration()) { + eventTimer = timer; + } + } + + char buf[100]; + string result; + sprintf(buf, "E%d", channel->Number()); + result = buf; + result += ":"; + result += channel->Name(); + result += ":"; + sprintf(buf, "%lu", event->StartTime()); + result += buf; + result += ":"; + sprintf(buf, "%lu", event->StartTime() + event->Duration()); + result += buf; + result += ":"; + result += MapSpecialChars(event->Title()); + result += ":"; + result += MapSpecialChars(event->Description() ? event->Description() : ""); + result += "\r\n"; + + if (eventTimer) { + result += ToText(eventTimer); + } + + return result; +} + +bool cHelpers::IsWantedEvent(cEvent * event, string pattern) { + + string text = event->Title(); + if (event->Description()) { + text += event->Description(); + } + + return ToUpper(text).find(ToUpper(pattern)) != string::npos; +} + +bool cHelpers::IsWantedChannel(cChannel * channel, string wantedChannels) { + + if (!channel) { + return false; + } + + if (wantedChannels.length() == 0) { + return true; + } + + int number = channel->Number(); + const char * delims = ",;"; + char * state; + char * buffer = (char *)malloc(wantedChannels.size()+1); + strcpy(buffer, wantedChannels.c_str()); + + bool found = false; + for(char * token = strtok_r(buffer, delims, &state); token; token = strtok_r(NULL, delims, &state)) { + const char * rangeSep = strchr(token, '-'); + if (rangeSep == NULL) { + // single channel + if (atoi(token) == number) { + found = true; + } + } else { + // channel range + int start = atoi(token); + while (*rangeSep && *rangeSep == '-') + rangeSep++; + int end = *rangeSep ? atoi(rangeSep) : INT_MAX; + + if (start <= number && number <= end) { + found = true; + } + } + } + return found; +} + +bool cHelpers::IsWantedTime(time_t when, cEvent * event) { + + time_t startTime = event->StartTime(); + time_t stopTime = startTime + event->Duration(); + + if (when == 0) { + return stopTime >= time(0); + } + + return startTime <= when && when < stopTime; +} + +string cHelpers::ToUpper(string text) +{ + for(unsigned i = 0; i < text.length(); i++) + { + if (islower(text[i])) + text[i] = toupper(text[i]); + } + + return text; +} + +string cHelpers::Trim(string text) { + + const char * start = text.c_str(); + + // skip leading spaces + const char * first = start; + while (*first && isspace(*first)) + first++; + + // find trailing spaces + const char * last = first + strlen(first) - 1; + while (first < last && isspace(*last)) + last--; + + char * dst = (char *)malloc(last - first + 2); + sprintf(dst, "%*s", last - first + 1, first); + + return dst; +} + +string cHelpers::SafeCall(string (*f)()) +{ + // loop, if vdr modified list and we crash + for (int i = 0; i < 3; i++) + { + try + { + return f(); + } + catch (...) + { + usleep(100); + } + } + + return ""; +} + +string cHelpers::SafeCall(string (*f)(string arg), string arg) +{ + // loop, if vdr modified list and we crash + for (int i = 0; i < 3; i++) + { + try + { + return f(arg); + } + catch (...) + { + usleep(100); + } + } + + return ""; +} + + +string cHelpers::SafeCall(string (*f)(string arg1, string arg2), string arg1, string arg2) +{ + // loop, if vdr modified list and we crash + for (int i = 0; i < 3; i++) + { + try + { + return f(arg1, arg2); + } + catch (...) + { + usleep(100); + } + } + + return ""; +} + +string cHelpers::MapSpecialChars(string text) { + + const char * p = text.c_str(); + string result = ""; + while (*p) { + switch (*p) { + case ':': + result += "|##"; + break; + case '\r': + break; + case '\n': + result += "||#"; + break; + default: + result += *p; + break; + } + p++; + } + return result; +} |