/* -*- c++ -*- Copyright (C) 2004-2013 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 #include #include #include #include #include #include "epgsearchtools.h" #include "recdone.h" #include "epgsearch.h" #include "changrp.h" #include "epgsearchcfg.h" #include "searchtimer_thread.h" #include "blacklist.h" #include "epgsearchcats.h" #include "menu_dirselect.h" #include "menu_deftimercheckmethod.h" #include "conflictcheck.h" #include "menu_main.h" using std::string; using std::set; template< class Iter > Iter advance_copy(Iter it, std::size_t count = 1) { using std::advance; advance(it, count); return it; } extern int updateForced; extern int exitToMainMenu; const char **cPluginEpgsearch::SVDRPHelpPages(void) { static const char *HelpPages[] = { "LSTS [ ID ]\n" " List searches.\n" " If the optional numeric argument ID is passed,\n" " only the search with the according ID is listed", "NEWS \n" " Add a new search\n", "DELS \n" " Delete search with passed ID\n", "EDIS \n" " Edit an existing search\n", "MODS ID ON|OFF\n" " Turn on/off 'Use as search timer'\n", "UPDS [ OSD ] [ SCAN ]\n" " Update search timers.\n" " If the optional keyword 'OSD' is passed, an OSD message\n" " will inform about update completion. With 'SCAN' you can\n" " trigger an EPG scan before the searchtimer udpate.", "UPDD\n" " Reload epgsearchdone.data", "SETS \n" " Temporarily activate or cancel the search timer background\n" " thread.", "FIND \n" " Search the EPG for events and receive a result list.", "QRYS < ID[|ID] >| \n" " Search the EPG for events and receive a result list\n" " for the given ID or any search settings. Separate multiple\n" " searches with '|'", "QRYF [hours]\n" " Search the EPG for favorite events with the next 24h or\n" " the given number of hours", "LSRD\n" " List of all recording directories used in recordings, timers,\n" " search timers or in epgsearchdirs.conf", "LSTC [ channel group name ]\n" " List all channel groups or if given the one with name\n" " group name.", "NEWC \n" " Create a new channel group, format as in\n" " epgsearchchangrps.conf.", "EDIC \n" " Modify an existing channel group, format as in\n" " epgsearchchangrps.conf.", "DELC \n" " Delete an existing channel group.", "RENC \n" " Rename an existing channel group.", "LSTB [ ID ]\n" " List blacklists.\n" " If the optional numeric argument ID is passed,\n" " only the blacklist with the according ID is listed", "NEWB \n" " Add a new blacklist", "DELB \n" " Delete blacklist with passed ID", "EDIB \n" " Edit an existing blacklist", "LSTE [ ID ]\n" " List the extended EPG categories defined in\n" " epgsearchcats.conf or only the one with the given ID", "SETP [ option ]\n" " Get the current setup option value", "LSTT [ ID ]\n" " List search templates.\n" " If the optional numeric argument ID is passed,\n" " only the search template with the according ID\n" " is listed", "NEWT \n" " Add a new search template\n", "DELT \n" " Delete search template with passed ID\n", "EDIT \n" " Edit an existing search template\n", "DEFT [ ID ]\n" " Returns the ID of the default search template\n" " or activates a search template with ID as default", "LSCC [ REL ]\n" " Returns the current (local) timer conflicts. With the option\n" " 'REL' only relevant conflicts are listed", "MENU [ NOW|PRG|SUM ]\n" " Calls one of the main menus of epgsearch or the summary\n" " of the current event\n", "UPDT\n" " Reload search timers from epgsearch.conf", NULL }; return HelpPages; } cString cPluginEpgsearch::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode) { if (strcasecmp(Command, "UPDS") == 0) { if (!EPGSearchConfig.useSearchTimers) // enable search timer thread if necessary cSearchTimerThread::Init((cPluginEpgsearch*) cPluginManager::GetPlugin("epgsearch"), true); updateForced = 1; if (Option) { char *pstrOptionToken, *pptr; char *pstrOptions = strdup(Option); pstrOptionToken = strtok_r(pstrOptions, " ", &pptr); while (pstrOptionToken) { if (strcasecmp(Option, "OSD") == 0) updateForced |= UPDS_WITH_OSD; if (strcasecmp(Option, "SCAN") == 0) updateForced |= UPDS_WITH_EPGSCAN; pstrOptionToken = strtok_r(NULL, "|", &pptr); } free(pstrOptions); } return cString("update triggered"); } else if (strcasecmp(Command, "UPDD") == 0) { if (RecsDone.Load(AddDirectory(CONFIGDIR, "epgsearchdone.data"))) return cString("reload successful"); else return cString("reload failed"); } // ----------------------- // search timer management else if (strcasecmp(Command, "LSTS") == 0) { if (*Option) { if (isnumber(Option)) { cSearchExt *search = SearchExts.GetSearchFromID(atol(Option)); if (search) return cString(search->ToText()); else { ReplyCode = 901; return cString::sprintf("search id %s not defined", Option); } } else { ReplyCode = 901; return cString::sprintf("Error in search ID \"%s\"", Option); } } else if (SearchExts.Count() > 0) { string sBuffer; cMutexLock SearchExtsLock(&SearchExts); for (int i = 0; i < SearchExts.Count(); i++) { cSearchExt* search = SearchExts.Get(i); if (search) sBuffer += string(search->ToText()) + string((i < SearchExts.Count() - 1) ? "\n" : ""); } return sBuffer.c_str(); } else { ReplyCode = 901; return cString("no searches defined"); } } else if (strcasecmp(Command, "DELS") == 0) { if (*Option) { string sOption = Option; bool delTimers = false; if (strcasestr(Option, "DELT")) { delTimers = true; sOption = ReplaceAll(sOption, "DELT", ""); sOption = Strip(sOption); } if (isnumber(sOption.c_str())) { long SID = atol(sOption.c_str()); cSearchExt *search = SearchExts.GetSearchFromID(SID); if (search) { LogFile.Log(1, "search '%s' deleted via SVDRP", search->search); cMutexLock SearchExtsLock(&SearchExts); if (delTimers) search->DeleteAllTimers(); SearchExts.Del(search); SearchExts.Save(); RecsDone.RemoveSearchID(SID); return cString::sprintf("search id %s deleted%s", sOption.c_str(), delTimers ? " with timers" : ""); } else { ReplyCode = 901; return cString::sprintf("search id %s not defined", sOption.c_str()); } } else { ReplyCode = 901; return cString::sprintf("Error in search ID \"%s\"", Option); } } else { ReplyCode = 901; return cString("missing search ID"); } } else if (strcasecmp(Command, "NEWS") == 0) { if (*Option) { cSearchExt* search = new cSearchExt; if (search->Parse(Option)) { search->ID = SearchExts.GetNewID(); LogFile.Log(1, "added search '%s' (%d) via SVDRP", search->search, search->ID); cMutexLock SearchExtsLock(&SearchExts); SearchExts.Add(search); SearchExts.Save(); if (search->useAsSearchTimer && !EPGSearchConfig.useSearchTimers) // enable search timer thread if necessary cSearchTimerThread::Init(this, true); return cString::sprintf("search '%s' (with new ID %d) added", search->search, search->ID); } else { ReplyCode = 901; delete search; return cString("Error in search settings"); } } else { ReplyCode = 901; return cString("missing search settings"); } } else if (strcasecmp(Command, "EDIS") == 0) { if (*Option) { cSearchExt* search = new cSearchExt; if (search->Parse(Option)) { cSearchExt *searchTemp = SearchExts.GetSearchFromID(search->ID); if (searchTemp) { searchTemp->Parse(Option); LogFile.Log(1, "modified search '%s' (%d) via SVDRP", searchTemp->search, searchTemp->ID); SearchExts.Save(); if (searchTemp->useAsSearchTimer && !EPGSearchConfig.useSearchTimers) // enable search timer thread if necessary cSearchTimerThread::Init((cPluginEpgsearch*) cPluginManager::GetPlugin("epgsearch"), true); return cString::sprintf("search '%s' with %d modified", searchTemp->search, searchTemp->ID); } else { ReplyCode = 901; int ID = search->ID; delete search; return cString::sprintf("search id %d does not exists", ID); } } else { ReplyCode = 901; delete search; return cString("Error in search settings"); } } else { ReplyCode = 901; return cString("missing search settings"); } } else if (strcasecmp(Command, "MODS") == 0) { if (*Option) { char *tail; int ID = strtol(Option, &tail, 10); tail = skipspace(tail); if (!*tail) { ReplyCode = 901; return cString::sprintf("missing parameter ON|OFF"); } cSearchExt *searchTemp = SearchExts.GetSearchFromID(ID); if (searchTemp) { searchTemp->useAsSearchTimer = (strcasecmp(tail, "ON") == 0) ? 1 : 0; LogFile.Log(1, "modified search '%s' (%d) via SVDRP", searchTemp->search, searchTemp->ID); SearchExts.Save(); if (searchTemp->useAsSearchTimer && !EPGSearchConfig.useSearchTimers) // enable search timer thread if necessary cSearchTimerThread::Init((cPluginEpgsearch*) cPluginManager::GetPlugin("epgsearch"), true); return cString::sprintf("search '%s' with ID %d modified", searchTemp->search, searchTemp->ID); } else { ReplyCode = 901; return cString::sprintf("search id %d does not exists", ID); } } else { ReplyCode = 901; return cString("missing search ID"); } } else if (strcasecmp(Command, "SETS") == 0) { if (*Option) { if (strcasecmp(Option, "ON") == 0) { if (cSearchTimerThread::m_Instance) { ReplyCode = 901; return cString("search timer thread already active!"); } else { LogFile.Log(1, "search timer thread started via SVDRP"); cSearchTimerThread::Init(this); return cString("search timer activated."); } } else if (strcasecmp(Option, "OFF") == 0) { if (!cSearchTimerThread::m_Instance) { ReplyCode = 901; return cString("search timer thread already inactive!"); } else { LogFile.Log(1, "search timer thread canceled via SVDRP"); cSearchTimerThread::Exit(); return cString("search timer thread canceled."); } } else { ReplyCode = 901; return cString::sprintf("unknown option '%s'", Option); } } else { ReplyCode = 901; return cString("missing option "); } } else if (strcasecmp(Command, "FIND") == 0) { if (*Option) { cSearchExt* search = new cSearchExt; if (search->Parse(Option)) { cSearchResults* results = search->Run(); // transfer to result list string sBuffer; if (results) { results->SortBy(CompareEventTime); cSearchResult *result = results->First(); while (result) { const cEvent* pEvent = result->event; cTimer* Timer = new cTimer(pEvent); static char bufStart[25]; static char bufEnd[25]; struct tm tm_r; time_t eStart = pEvent->StartTime(); time_t eStop = pEvent->EndTime(); time_t start = eStart - (search->MarginStart * 60); time_t stop = eStop + (search->MarginStop * 60); int Flags = Timer->Flags(); if (search->useVPS && pEvent->Vps() && Setup.UseVps) { start = pEvent->Vps(); stop = start + pEvent->Duration(); } else Flags = 1; // don't use VPS, if not set in this search strftime(bufStart, sizeof(bufStart), "%H%M", localtime_r(&start, &tm_r)); strftime(bufEnd, sizeof(bufEnd), "%H%M", localtime_r(&stop, &tm_r)); cString cmdbuf = cString::sprintf("NEWT %d:%d:%s:%s:%s:%d:%d:%s:%s", Flags, Timer->Channel()->Number(), *Timer->PrintDay(start, Timer->WeekDays(), true), bufStart, bufEnd, search->Priority, search->Lifetime, Timer->File(), ""); sBuffer += string(cmdbuf) + string(results->Next(result) ? "\n" : ""); delete(Timer); result = results->Next(result); } return sBuffer.c_str(); } else { ReplyCode = 901; delete search; return cString("no results"); } } else { ReplyCode = 901; delete search; return cString("Error in search settings"); } } else { ReplyCode = 901; return cString("missing search settings"); } } else if (strcasecmp(Command, "QRYS") == 0 || strcasecmp(Command, "QRYF") == 0) { cSearchExt *temp_SearchExt = NULL; cSearchResults* pCompleteSearchResults = NULL; if (strcasecmp(Command, "QRYS") == 0) { // query one or more searches if (*Option) { if (strchr(Option, ':')) { cSearchExt* temp_SearchExt = new cSearchExt; if (temp_SearchExt->Parse(Option)) pCompleteSearchResults = temp_SearchExt->Run(); } else { char *pstrSearchToken, *pptr; char *pstrSearch = strdup(Option); pstrSearchToken = strtok_r(pstrSearch, "|", &pptr); while (pstrSearchToken) { cSearchExt* search = SearchExts.GetSearchFromID(atoi(pstrSearchToken)); if (search) pCompleteSearchResults = search->Run(-1, false, 0, pCompleteSearchResults); pstrSearchToken = strtok_r(NULL, "|", &pptr); } free(pstrSearch); } } else { ReplyCode = 901; return cString("missing search IDs"); } } else { // query the favorites int hours = EPGSearchConfig.FavoritesMenuTimespan; if (*Option) hours = atoi(Option); cMutexLock SearchExtsLock(&SearchExts); cSearchExt *SearchExt = SearchExts.First(); while (SearchExt) { if (SearchExt->useInFavorites) pCompleteSearchResults = SearchExt->Run(-1, false, 60 * hours, pCompleteSearchResults); SearchExt = SearchExts.Next(SearchExt); } } if (pCompleteSearchResults) { // transfer to result list string sBuffer; pCompleteSearchResults->SortBy(CompareEventTime); cSearchResult *result = pCompleteSearchResults->First(); while (result && result->search) { const cEvent* pEvent = result->event; cTimer* Timer = new cTimer(pEvent); static char bufStart[25]; static char bufEnd[25]; struct tm tm_r; time_t eStart = pEvent->StartTime(); time_t eStop = pEvent->EndTime(); time_t start = eStart - (result->search->MarginStart * 60); time_t stop = eStop + (result->search->MarginStop * 60); if (result->search->useVPS && pEvent->Vps() && Setup.UseVps) { start = pEvent->Vps(); stop = start + pEvent->Duration(); } strftime(bufStart, sizeof(bufStart), "%H%M", localtime_r(&start, &tm_r)); strftime(bufEnd, sizeof(bufEnd), "%H%M", localtime_r(&stop, &tm_r)); eTimerMatch timerMatch; bool hasTimer = false; LOCK_TIMERS_READ; if (Timers->GetMatch(pEvent, &timerMatch)) hasTimer = (timerMatch == tmFull); if (!result->search->useAsSearchTimer) result->needsTimer = false; LOCK_CHANNELS_READ; const cChannel *channel = Channels->GetByChannelID(pEvent->ChannelID(), true, true); int timerMode = hasTimer ? 1 : (result->needsTimer ? 2 : 0); string title = pEvent->Title() ? ReplaceAll(pEvent->Title(), "|", "!^pipe!^") : ""; title = ReplaceAll(title, ":", "|"); string shorttext = pEvent->ShortText() ? ReplaceAll(pEvent->ShortText(), "|", "!^pipe!^") : ""; shorttext = ReplaceAll(shorttext, ":", "|"); cString cmdbuf = cString::sprintf("%d:%u:%s:%s:%ld:%ld:%s:%ld:%ld:%s:%d", result->search->ID, pEvent->EventID(), title.c_str(), shorttext.c_str(), pEvent->StartTime(), pEvent->EndTime(), CHANNELSTRING(channel), timerMode > 0 ? start : -1, timerMode > 0 ? stop : -1, timerMode > 0 ? result->search->BuildFile(pEvent) : "", timerMode); sBuffer += string(cmdbuf) + string(pCompleteSearchResults->Next(result) ? "\n" : ""); delete(Timer); result = pCompleteSearchResults->Next(result); } if (temp_SearchExt) delete temp_SearchExt; if (pCompleteSearchResults) delete pCompleteSearchResults; return sBuffer.c_str(); } else { ReplyCode = 901; if (temp_SearchExt) delete temp_SearchExt; return cString("no results"); } } else if (strcasecmp(Command, "UPDT") == 0) { if (SearchExts.Load(AddDirectory(CONFIGDIR, "epgsearch.conf"))) return cString("reload epgsearch.conf successful"); else return cString("reload epgsearch.conf failed"); } // --------------------- // recording directories else if (strcasecmp(Command, "LSRD") == 0) { cMenuDirSelect::CreateDirSet(); if (cMenuDirSelect::directorySet.size() > 0) { cString sBuffer(""); std::set::iterator it; for (it = cMenuDirSelect::directorySet.begin(); it != cMenuDirSelect::directorySet.end(); ++it) { cString sOldBuffer = sBuffer; sBuffer = cString::sprintf("%s%s\n", *sOldBuffer, (*it).c_str()); } char* buffer = strdup(*sBuffer); cString sResBuffer = cString(buffer); free(buffer); return sResBuffer; } else { ReplyCode = 901; return cString("no recording directories found"); } } // ------------------------- // channel groups management else if (strcasecmp(Command, "LSTC") == 0) { if (*Option) { cChannelGroup *changrp = ChannelGroups.GetGroupByName(Option); if (changrp) return cString(changrp->ToText()); else { ReplyCode = 901; return cString::sprintf("channel group '%s' not defined", Option); } } else if (ChannelGroups.Count() > 0) { cString sBuffer(""); for (int i = 0; i < ChannelGroups.Count(); i++) { cChannelGroup *changrp = ChannelGroups.Get(i); if (changrp) { cString sOldBuffer = sBuffer; sBuffer = cString::sprintf("%s%s\n", *sOldBuffer, changrp->ToText()); } } char* buffer = strdup(*sBuffer); cString sResBuffer = cString(buffer); free(buffer); return sResBuffer; } else { ReplyCode = 901; return cString("no channel groups defined"); } } else if (strcasecmp(Command, "EDIC") == 0) { if (*Option) { cChannelGroup *changrp = new cChannelGroup; if (changrp->Parse(Option)) { cChannelGroup *changrpTemp = ChannelGroups.GetGroupByName(changrp->name); if (changrpTemp) { changrpTemp->channels.Clear(); changrpTemp->Parse(Option); LogFile.Log(1, "modified channel group '%s' via SVDRP", changrpTemp->name); ChannelGroups.Save(); return cString::sprintf("channel group '%s' modified", changrpTemp->name); } else { ReplyCode = 901; delete changrp; return cString::sprintf("channel group '%s' does not exists", Option); } } else { ReplyCode = 901; delete changrp; return cString("Error in channel group settings"); } } else { ReplyCode = 901; return cString("missing channel group settings"); } } else if (strcasecmp(Command, "DELC") == 0) { if (*Option) { cChannelGroup *changrp = ChannelGroups.GetGroupByName(Option); if (changrp) { cSearchExt* search = ChannelGroups.Used(changrp); if (search) { ReplyCode = 901; return cString::sprintf("channel group '%s' used by: %s", changrp->name, search->search); } LogFile.Log(1, "channel group '%s' deleted via SVDRP", changrp->name); ChannelGroups.Del(changrp); ChannelGroups.Save(); return cString::sprintf("channel group '%s' deleted", Option); } else { ReplyCode = 901; return cString::sprintf("channel group '%s' not defined", Option); } } else { ReplyCode = 901; return cString("missing channel group"); } } else if (strcasecmp(Command, "NEWC") == 0) { if (*Option) { cChannelGroup *changrp = new cChannelGroup; if (changrp->Parse(Option)) { LogFile.Log(1, "added channel group '%s' via SVDRP", changrp->name); ChannelGroups.Add(changrp); ChannelGroups.Save(); return cString::sprintf("channel group '%s' added", changrp->name); } else { ReplyCode = 901; delete changrp; return cString("Error in channel group settings"); } } else { ReplyCode = 901; return cString("missing channel group settings"); } } else if (strcasecmp(Command, "RENC") == 0) { if (*Option) { const char* pipePos = strchr(Option, '|'); if (pipePos) { int index = pipePos - Option; char* oldName = strdup(Option); *(oldName + index) = 0; const char* newName = oldName + index + 1; if (strlen(oldName) > 0 && strlen(newName) > 0) { cChannelGroup *changrp = ChannelGroups.GetGroupByName(oldName); if (changrp) { strcpy(changrp->name, newName); cMutexLock SearchExtsLock(&SearchExts); cSearchExt *SearchExt = SearchExts.First(); while (SearchExt) { if (SearchExt->useChannel == 2 && SearchExt->channelGroup && strcmp(SearchExt->channelGroup, oldName) == 0) { free(SearchExt->channelGroup); SearchExt->channelGroup = strdup(newName); } SearchExt = SearchExts.Next(SearchExt); } ChannelGroups.Save(); SearchExts.Save(); cString strReturn = cString::sprintf("renamed channel group '%s' to '%s'", oldName, newName); free(oldName); return strReturn; } else { free(oldName); ReplyCode = 901; return cString::sprintf("channel group '%s' not defined", Option); } } free(oldName); } ReplyCode = 901; return cString("Error in channel group parameters"); } else { ReplyCode = 901; return cString("missing channel group parameters"); } } // -------------------- // blacklist management else if (strcasecmp(Command, "LSTB") == 0) { if (*Option) { if (isnumber(Option)) { cBlacklist *blacklist = Blacklists.GetBlacklistFromID(atol(Option)); if (blacklist) return cString(blacklist->ToText()); else { ReplyCode = 901; return cString::sprintf("blacklist id %s not defined", Option); } } else { ReplyCode = 901; return cString::sprintf("Error in blacklist ID \"%s\"", Option); } } else if (Blacklists.Count() > 0) { cMutexLock BlacklistLock(&Blacklists); string sBuffer; for (int i = 0; i < Blacklists.Count(); i++) { cBlacklist *blacklist = Blacklists.Get(i); if (blacklist) sBuffer += string(blacklist->ToText()) + string((i < Blacklists.Count() - 1) ? "\n" : ""); } return sBuffer.c_str(); } else { ReplyCode = 901; return cString("no blacklists defined"); } } else if (strcasecmp(Command, "DELB") == 0) { if (*Option) { if (isnumber(Option)) { cBlacklist *blacklist = Blacklists.GetBlacklistFromID(atol(Option)); if (blacklist) { LogFile.Log(1, "blacklist '%s' deleted via SVDRP", blacklist->search); SearchExts.RemoveBlacklistID(blacklist->ID); cMutexLock BlacklistLock(&Blacklists); Blacklists.Del(blacklist); Blacklists.Save(); RecsDone.RemoveSearchID(atol(Option)); return cString::sprintf("blacklist id %s deleted", Option); } else { ReplyCode = 901; return cString::sprintf("blacklist id %s not defined", Option); } } else { ReplyCode = 901; return cString::sprintf("Error in blacklist ID \"%s\"", Option); } } else { ReplyCode = 901; return cString("missing blacklist ID"); } } else if (strcasecmp(Command, "NEWB") == 0) { if (*Option) { cBlacklist *blacklist = new cBlacklist; if (blacklist->Parse(Option)) { blacklist->ID = Blacklists.GetNewID(); LogFile.Log(1, "added blacklist '%s' (%d) via SVDRP", blacklist->search, blacklist->ID); cMutexLock BlacklistLock(&Blacklists); Blacklists.Add(blacklist); Blacklists.Save(); return cString::sprintf("blacklist '%s' (with new ID %d) added", blacklist->search, blacklist->ID); } else { ReplyCode = 901; delete blacklist; return cString("Error in blacklist settings"); } } else { ReplyCode = 901; return cString("missing blacklist settings"); } } else if (strcasecmp(Command, "EDIB") == 0) { if (*Option) { cBlacklist *blacklist = new cBlacklist; if (blacklist->Parse(Option)) { cBlacklist *blacklistTemp = Blacklists.GetBlacklistFromID(blacklist->ID); if (blacklistTemp) { blacklistTemp->Parse(Option); LogFile.Log(1, "modified blacklist '%s' (%d) via SVDRP", blacklistTemp->search, blacklistTemp->ID); Blacklists.Save(); return cString::sprintf("blacklist '%s' with ID %d modified", blacklistTemp->search, blacklistTemp->ID); } else { ReplyCode = 901; int ID = blacklist->ID; delete blacklist; return cString::sprintf("blacklist id %d does not exists", ID); } } else { ReplyCode = 901; delete blacklist; return cString("Error in blacklist settings"); } } else { ReplyCode = 901; return cString("missing blacklist settings"); } } // ---------------------------------- // extended EPG categories management else if (strcasecmp(Command, "LSTE") == 0) { if (*Option) { if (isnumber(Option)) { cSearchExtCat *SearchExtCat = NULL; int index = SearchExtCats.GetIndexFromID(atoi(Option)); if (index >= 0) SearchExtCat = SearchExtCats.Get(index); if (SearchExtCat) return cString(SearchExtCat->ToText()); else { ReplyCode = 901; return cString::sprintf("category id %s not defined", Option); } } else { ReplyCode = 901; return cString::sprintf("Error in category ID \"%s\"", Option); } } else if (SearchExtCats.Count() > 0) { string sBuffer; for (int i = 0; i < SearchExtCats.Count(); i++) { cSearchExtCat *SearchExtCat = SearchExtCats.Get(i); if (SearchExtCat) sBuffer += string(SearchExtCat->ToText()) + string((i < SearchExtCats.Count() - 1) ? "\n" : ""); } return sBuffer.c_str(); } else { ReplyCode = 901; return cString("no EPG categories defined"); } } // ------------ // setup values else if (strcasecmp(Command, "SETP") == 0) { if (*Option) { if (strcasecmp(Option, "ShowFavoritesMenu") == 0) return cString::sprintf("%d", EPGSearchConfig.showFavoritesMenu); else if (strcasecmp(Option, "UseSearchTimers") == 0) return cString::sprintf("%d", EPGSearchConfig.useSearchTimers); else if (strcasecmp(Option, "DefRecordingDir") == 0) { if (strlen(EPGSearchConfig.defrecdir) > 0) return cString::sprintf("%s", EPGSearchConfig.defrecdir); else { ReplyCode = 901; return cString::sprintf("empty"); } } else if (strcasecmp(Option, "AddSubtitleToTimerMode") == 0) return cString::sprintf("%d", EPGSearchConfig.addSubtitleToTimer); else if (strcasecmp(Option, "DefPriority") == 0) return cString::sprintf("%d", EPGSearchConfig.DefPriority); else if (strcasecmp(Option, "DefLifetime") == 0) return cString::sprintf("%d", EPGSearchConfig.DefLifetime); else if (strcasecmp(Option, "DefMarginStart") == 0) return cString::sprintf("%d", EPGSearchConfig.DefMarginStart); else if (strcasecmp(Option, "DefMarginStop") == 0) return cString::sprintf("%d", EPGSearchConfig.DefMarginStop); else if (strcasestr(Option, "DefTimerCheckMethod") == Option) { tChannelID chID; if (strlen(Option) > strlen("DefTimerCheckMethod") + 1) { chID = tChannelID::FromString(Option + strlen("DefTimerCheckMethod") + 1); if (!chID.Valid()) { ReplyCode = 901; return cString::sprintf("invalid channel id"); } LOCK_CHANNELS_READ; const cChannel *ch = Channels->GetByChannelID(chID, true, true); if (!ch) { ReplyCode = 901; return cString::sprintf("unknown channel"); } return cString::sprintf("%s: %d", *ch->GetChannelID().ToString(), DefTimerCheckModes.GetMode(ch)); } else { LOCK_CHANNELS_READ; string sBuffer; for (int i = 0; i < Channels->Count(); i++) { const cChannel* ch = Channels->Get(i); if (ch && !ch->GroupSep()) sBuffer += string(*ch->GetChannelID().ToString()) + string(": ") + NumToString(DefTimerCheckModes.GetMode(ch)) + string((i < Channels->Count() - 1) ? "\n" : ""); } return sBuffer.c_str(); } } else { ReplyCode = 901; return cString::sprintf("setup option not supported"); } } else { string sBuffer; sBuffer += "ShowFavoritesMenu: " + NumToString(EPGSearchConfig.showFavoritesMenu) + "\n"; sBuffer += "UseSearchTimers: " + NumToString(EPGSearchConfig.useSearchTimers) + "\n"; sBuffer += "DefRecordingDir: " + string(EPGSearchConfig.defrecdir) + "\n"; sBuffer += "AddSubtitleToTimerMode: " + NumToString(EPGSearchConfig.addSubtitleToTimer) + "\n"; sBuffer += "DefPriority: " + NumToString(EPGSearchConfig.DefPriority) + "\n"; sBuffer += "DefLifetime: " + NumToString(EPGSearchConfig.DefLifetime) + "\n"; sBuffer += "DefMarginStart: " + NumToString(EPGSearchConfig.DefMarginStart) + "\n"; sBuffer += "DefMarginStop: " + NumToString(EPGSearchConfig.DefMarginStop); return sBuffer.c_str(); } } // --------------------------------- // search timer templates management else if (strcasecmp(Command, "LSTT") == 0) { if (*Option) { if (isnumber(Option)) { cSearchExt *search = SearchTemplates.GetSearchFromID(atol(Option)); if (search) return cString(search->ToText()); else { ReplyCode = 901; return cString::sprintf("search template id %s not defined", Option); } } else { ReplyCode = 901; return cString::sprintf("Error in search template ID \"%s\"", Option); } } else if (SearchTemplates.Count() > 0) { string sBuffer; cMutexLock SearchExtsLock(&SearchTemplates); for (int i = 0; i < SearchTemplates.Count(); i++) { cSearchExt* search = SearchTemplates.Get(i); if (search) sBuffer += string(search->ToText()) + string((i < SearchTemplates.Count() - 1) ? "\n" : ""); } return sBuffer.c_str(); } else { ReplyCode = 901; return cString("no search templates defined"); } } else if (strcasecmp(Command, "DELT") == 0) { if (*Option) { if (isnumber(Option)) { cSearchExt *search = SearchTemplates.GetSearchFromID(atoi(Option)); if (search) { LogFile.Log(1, "search template '%s' deleted via SVDRP", search->search); cMutexLock SearchExtsLock(&SearchTemplates); SearchTemplates.Del(search); SearchTemplates.Save(); return cString::sprintf("search template id %s deleted", Option); } else { ReplyCode = 901; return cString::sprintf("search template id %s not defined", Option); } } else { ReplyCode = 901; return cString::sprintf("Error in search template ID \"%s\"", Option); } } else { ReplyCode = 901; return cString("missing search template ID"); } } else if (strcasecmp(Command, "NEWT") == 0) { if (*Option) { cSearchExt* search = new cSearchExt; if (search->Parse(Option)) { search->ID = SearchTemplates.GetNewID(); LogFile.Log(1, "added search template '%s' (%d) via SVDRP", search->search, search->ID); cMutexLock SearchExtsLock(&SearchTemplates); SearchTemplates.Add(search); SearchTemplates.Save(); return cString::sprintf("search template '%s' (with new ID %d) added", search->search, search->ID); } else { ReplyCode = 901; delete search; return cString("Error in search template settings"); } } else { ReplyCode = 901; return cString("missing search template settings"); } } else if (strcasecmp(Command, "EDIT") == 0) { if (*Option) { cSearchExt* search = new cSearchExt; if (search->Parse(Option)) { cSearchExt *searchTemp = SearchTemplates.GetSearchFromID(search->ID); if (searchTemp) { searchTemp->Parse(Option); LogFile.Log(1, "modified search template '%s' (%d) via SVDRP", searchTemp->search, searchTemp->ID); SearchTemplates.Save(); return cString::sprintf("search template '%s' with ID %d modified", searchTemp->search, searchTemp->ID); } else { ReplyCode = 901; int ID = search->ID; delete search; return cString::sprintf("search template id %d does not exists", ID); } } else { ReplyCode = 901; delete search; return cString("Error in search template settings"); } } else { ReplyCode = 901; return cString("missing search template settings"); } } else if (strcasecmp(Command, "DEFT") == 0) { if (*Option) { cSearchExt *searchTemp = SearchTemplates.GetSearchFromID(atoi(Option)); if (searchTemp) { LogFile.Log(1, "set search template '%s' (%d) as default via SVDRP", searchTemp->search, searchTemp->ID); EPGSearchConfig.DefSearchTemplateID = searchTemp->ID; cPluginManager::GetPlugin("epgsearch")->SetupStore("DefSearchTemplateID", EPGSearchConfig.DefSearchTemplateID); return cString::sprintf("search template '%s' with ID %d set as default", searchTemp->search, searchTemp->ID); } else { ReplyCode = 901; return cString::sprintf("search template id %s does not exists", Option); } } else return cString::sprintf("%d", EPGSearchConfig.DefSearchTemplateID); } // --------------------------------- // timer conflicts else if (strcasecmp(Command, "LSCC") == 0) { bool relOnly = false; if (*Option && strcasecmp(Option, "REL") == 0) relOnly = true; LogFile.Log(3, "svdrp LSCC"); cConflictCheck conflictCheck; conflictCheck.SetLocal(); // including remote timers results in an infinite loop conflictCheck.Check(); if ((relOnly && conflictCheck.numConflicts > 0) || conflictCheck.relevantConflicts > 0) { string sBuffer; cList* failedList = conflictCheck.GetFailed(); for (cConflictCheckTime* ct = failedList->First(); ct; ct = failedList->Next(ct)) { if (relOnly && ct->ignore) continue; std::ostringstream conflline; conflline << ct->evaltime << ":"; std::set::iterator it; std::ostringstream timerparts; for (it = ct->failedTimers.begin(); it != ct->failedTimers.end(); ++it) { if (relOnly && (*it)->ignore) continue; std::ostringstream timerpart; int recPart = (*it)->recDuration * 100 / ((*it)->stop - (*it)->start); timerpart << (*it)->timer->Id() << "|" << recPart << "|"; std::set::iterator itcc; if ((*it)->concurrentTimers) { std::ostringstream cctimers; for (itcc = (*it)->concurrentTimers->begin(); itcc != (*it)->concurrentTimers->end(); ++itcc) cctimers << (cctimers.str().empty() ? "" : "#") << (*itcc)->timer->Id(); timerpart << cctimers.str(); } timerparts << (timerparts.str().empty() ? "" : ":") << timerpart.str(); } conflline << timerparts.str(); sBuffer += conflline.str() + "\n"; } return sBuffer.c_str(); } else { ReplyCode = 901; return cString("no conflicts found"); } } else if (strcasecmp(Command, "MENU") == 0) { if (*Option) { if (cMenuSearchMain::forceMenu == 0) { if (strcasecmp(Option, "PRG") == 0) cMenuSearchMain::forceMenu = 2; else if (strcasecmp(Option, "NOW") == 0) cMenuSearchMain::forceMenu = 1; else if (strcasecmp(Option, "SUM") == 0) cMenuSearchMain::forceMenu = 3; else { ReplyCode = 901; return cString::sprintf("unknown option '%s'", Option); } cRemote::CallPlugin("epgsearch"); return "menu called"; } else { cRemote::Put(kBack); exitToMainMenu = 1; return "menu closed"; } } } return NULL; }