/* Copyright (C) 2004-2008 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" 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; 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 ]\n" " Update search timers.\n" " If the optional keyword 'OSD' is passed, an OSD message\n" " will inform about update completion.", "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 timer conflicts. With the option\n" " 'REL' only relevant conflicts are listed", NULL }; return HelpPages; } cString cPluginEpgsearch::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode) { if (strcasecmp(Command, "UPDS") == 0) { updateForced = (Option && strcasecmp(Option, "OSD") == 0)?2:1; 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((isearch); cMutexLock SearchExtsLock(&SearchExts); if (delTimers && !Timers.BeingEdited()) 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(), #if VDRVERSNUM < 10503 *Timer->PrintDay(start, Timer->WeekDays()), #else *Timer->PrintDay(start, Timer->WeekDays(), true), #endif 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)); int timerMatch; bool hasTimer = false; if (Timers.GetMatch(pEvent, &timerMatch)) hasTimer = (timerMatch == tmFull); if (!result->search->useAsSearchTimer) result->needsTimer = false; 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"); } } // --------------------- // 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) { char* pipePos = strchr(Option, '|'); if (pipePos) { *pipePos = 0; const char* oldName = Option; const char* newName = pipePos+1; if (strlen(oldName) > 0 && strlen(newName) > 0) { cChannelGroup *changrp = ChannelGroups.GetGroupByName(Option); 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(); return cString::sprintf("renamed channel group '%s' to '%s'", oldName, newName); } else { ReplyCode = 901; return cString::sprintf("channel group '%s' not defined", Option); } } } 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((isearch); 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((i0) 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"); } 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 { string sBuffer; for (int i = 0; i < Channels.Count(); i++) { cChannel* ch = Channels.Get(i); if (ch && !ch->GroupSep()) sBuffer += string(*ch->GetChannelID().ToString()) + string(": ") + NumToString(DefTimerCheckModes.GetMode(ch)) + string((iToText()); 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((isearch); 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; cConflictCheck conflictCheck; 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->Index()+1 << "|" << 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->Index()+1; 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"); } } return NULL; }