diff --git a/HISTORY b/HISTORY index aa13be2c..387a7885 100644 --- a/HISTORY +++ b/HISTORY @@ -8669,8 +8669,10 @@ Video Disk Recorder Revision History connections to keep them alive. - The new function GetSVDRPServerNames() can be used to get a list of all VDRs this VDR is connected to via SVDRP. -- The new class cSVDRPCommand can be used to execute an SVDRP command on one of - the servers this VDR is connected to, and retrieve the result. +- The new function ExecSVDRPCommand() can be used to execute an SVDRP command on + one of the servers this VDR is connected to, and retrieve the result. + The helper functions SVDRPCode() and SVDRPValue() can be used to easily access + the codes and values returned by ExecSVDRPCommand(). - The cTimer class now has a new member named 'remote', which holds the name of the remote server this timer will record on. If this is NULL, it is a local timer. - Timers from other VDRs that are connected to this VDR via SVDRP are now @@ -8795,3 +8797,13 @@ Video Disk Recorder Revision History ".../SVDRP default host" can be used to configure automatic peering between VDRs in the same network. Peering is disabled by default and can be enabled by setting "SVDRP peering" to "yes". +- The function cTimer::ToText() no longer returns a newline character at the end of + the string. The newline is now added by the caller as necessary. This was changed + because cTimer::ToText() is now also needed in a context where the terminating + newline can't be used. Consequently, cChannel::ToText() and cMark::ToText() have + been modified accordingly. +- The "Edit timer" menu now has a new parameter "Record on", which can be used to + select the VDR on which this timer shall record. Timers can be freely moved + between connected VDRs by simply selecting the desired machine in this field. +- The SVDRP command DELT no longer checks whether the timer that shall be deleted + is currently recording. diff --git a/MANUAL b/MANUAL index e956c29e..d5d658ff 100644 --- a/MANUAL +++ b/MANUAL @@ -498,6 +498,9 @@ Version 2.2 the name of the recording. First day: The date of the first day when this timer shall start recording (only available for repeating timers). + Record on: The name of the remote VDR this timer shall record on (only available + if there are any remote VDRs connected to this VDR). If this field + is empty, the timer will record on the local VDR. A timer can also be programmed by pressing the "Red" key on the "Schedule", "Now", "Next" or "Event" menus. diff --git a/channels.c b/channels.c index 005f28c9..24fec5be 100644 --- a/channels.c +++ b/channels.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: channels.c 4.2 2015/08/29 12:16:24 kls Exp $ + * $Id: channels.c 4.3 2015/09/09 10:21:22 kls Exp $ */ #include "channels.h" @@ -554,9 +554,9 @@ cString cChannel::ToText(const cChannel *Channel) cString buffer; if (Channel->groupSep) { if (Channel->number) - buffer = cString::sprintf(":@%d %s\n", Channel->number, FullName); + buffer = cString::sprintf(":@%d %s", Channel->number, FullName); else - buffer = cString::sprintf(":%s\n", FullName); + buffer = cString::sprintf(":%s", FullName); } else { char vpidbuf[32]; @@ -588,7 +588,7 @@ cString cChannel::ToText(const cChannel *Channel) q = caidbuf; q += IntArrayToString(q, Channel->caids, 16); *q = 0; - buffer = cString::sprintf("%s:%d:%s:%s:%d:%s:%s:%s:%s:%d:%d:%d:%d\n", FullName, Channel->frequency, *Channel->parameters, *cSource::ToString(Channel->source), Channel->srate, vpidbuf, apidbuf, tpidbuf, caidbuf, Channel->sid, Channel->nid, Channel->tid, Channel->rid); + buffer = cString::sprintf("%s:%d:%s:%s:%d:%s:%s:%s:%s:%d:%d:%d:%d", FullName, Channel->frequency, *Channel->parameters, *cSource::ToString(Channel->source), Channel->srate, vpidbuf, apidbuf, tpidbuf, caidbuf, Channel->sid, Channel->nid, Channel->tid, Channel->rid); } return buffer; } @@ -806,7 +806,7 @@ bool cChannel::Parse(const char *s) bool cChannel::Save(FILE *f) { - return fprintf(f, "%s", *ToText()) > 0; + return fprintf(f, "%s\n", *ToText()) > 0; } // --- cChannelSorter -------------------------------------------------------- diff --git a/menu.c b/menu.c index eb49c665..2aac2054 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 4.5 2015/09/08 11:02:52 kls Exp $ + * $Id: menu.c 4.6 2015/09/10 10:34:45 kls Exp $ */ #include "menu.h" @@ -999,6 +999,15 @@ cMenuEditTimer::cMenuEditTimer(cTimer *Timer, bool New) Add(new cMenuEditIntItem( tr("Lifetime"), &data.lifetime, 0, MAXLIFETIME)); Add(file = new cMenuEditStrItem( tr("File"), data.file, sizeof(data.file))); SetFirstDayItem(); + if (data.remote) + strn0cpy(remote, data.remote, sizeof(remote)); + else + *remote = 0; + if (GetSVDRPServerNames(&svdrpServerNames)) { + svdrpServerNames.Sort(true); + svdrpServerNames.Insert(strdup("")); + Add(new cMenuEditStrlItem(tr("Record on"), remote, sizeof(remote), &svdrpServerNames)); + } } SetHelpKeys(); } @@ -1053,6 +1062,70 @@ eOSState cMenuEditTimer::SetFolder(void) return CloseSubMenu(); } +static bool RemoteTimerError(const cTimer *Timer) +{ + Skins.Message(mtError, cString::sprintf(tr("Error while accessing remote timer %d@%s!"), Timer->Id(), Timer->Remote())); + return false; // convenience return code +} + +bool cMenuEditTimer::HandleRemoteModifications(cTimer *OldTimer, cTimer *NewTimer) +{ + cStringList Response; + if (OldTimer->Local()) { + if (NewTimer->Local()) { // timer stays local, nothing to do + } + else { // timer is moved from local to remote + if (!ExecSVDRPCommand(NewTimer->Remote(), cString::sprintf("NEWT %s", *NewTimer->ToText(true)), &Response) || SVDRPCode(Response[0]) != 250) + return RemoteTimerError(NewTimer); + int RemoteId = atoi(SVDRPValue(Response[0])); + if (RemoteId <= 0) + return RemoteTimerError(NewTimer); + NewTimer->SetId(RemoteId); + isyslog("moved timer %s to %d@%s", *OldTimer->ToDescr(), NewTimer->Id(), NewTimer->Remote()); + } + } + else if (NewTimer->Local()) { // timer is moved from remote to local + if (OldTimer->Id()) { // its an existing timer + if (!ExecSVDRPCommand(OldTimer->Remote(), cString::sprintf("DELT %d", OldTimer->Id()), &Response) || SVDRPCode(Response[0]) != 250) + return RemoteTimerError(OldTimer); + } + NewTimer->SetId(cTimers::NewTimerId()); + isyslog("moved timer %d@%s to %s", OldTimer->Id(), OldTimer->Remote(), *NewTimer->ToDescr()); + } + else if (strcmp(OldTimer->Remote(), NewTimer->Remote()) == 0) { // timer stays remote on same machine + if (OldTimer->Id()) { // its an existing timer + if (!ExecSVDRPCommand(OldTimer->Remote(), cString::sprintf("MODT %d %s", OldTimer->Id(), *NewTimer->ToText(true)), &Response) || SVDRPCode(Response[0]) != 250) + return RemoteTimerError(NewTimer); + isyslog("modified timer %s", *NewTimer->ToDescr()); + } + else { // its a new timer + if (!ExecSVDRPCommand(NewTimer->Remote(), cString::sprintf("NEWT %s", *NewTimer->ToText(true)), &Response) || SVDRPCode(Response[0]) != 250) + return RemoteTimerError(NewTimer); + int RemoteId = atoi(SVDRPValue(Response[0])); + if (RemoteId <= 0) + return RemoteTimerError(NewTimer); + NewTimer->SetId(RemoteId); + isyslog("added timer %s", *NewTimer->ToDescr()); + } + } + else { // timer is moved from one remote machine to an other + if (!ExecSVDRPCommand(NewTimer->Remote(), cString::sprintf("NEWT %s", *NewTimer->ToText(true)), &Response) || SVDRPCode(Response[0]) != 250) + return RemoteTimerError(NewTimer); + int RemoteId = atoi(SVDRPValue(Response[0])); + if (RemoteId <= 0) + return RemoteTimerError(NewTimer); + NewTimer->SetId(RemoteId); + if (OldTimer->Id()) { // its an existing timer + if (!ExecSVDRPCommand(OldTimer->Remote(), cString::sprintf("DELT %d", OldTimer->Id()), &Response) || SVDRPCode(Response[0]) != 250) + return RemoteTimerError(OldTimer); + isyslog("moved timer %d@%s to %s", OldTimer->Id(), OldTimer->Remote(), *NewTimer->ToDescr()); + } + else // its a new timer + isyslog("added timer %s", *NewTimer->ToDescr()); + } + return true; +} + eOSState cMenuEditTimer::ProcessKey(eKeys Key) { eOSState state = cOsdMenu::ProcessKey(Key); @@ -1074,6 +1147,9 @@ eOSState cMenuEditTimer::ProcessKey(eKeys Key) } if (!*data.file) strcpy(data.file, data.Channel()->ShortName(true)); + data.SetRemote(*remote ? remote : NULL); + if (!HandleRemoteModifications(timer, &data)) + return osContinue; *timer = data; if (addIfConfirmed) { Timers->Add(timer); @@ -1215,7 +1291,7 @@ void cMenuTimers::Set(void) for (const cTimer *Timer = Timers->First(); Timer; Timer = Timers->Next(Timer)) { cMenuTimerItem *Item = new cMenuTimerItem(Timer); Add(Item); - if (Timer == CurrentTimer) + if (CurrentTimer && Timer->Id() == CurrentTimer->Id() && (!Timer->Remote() && !CurrentTimer->Remote() || Timer->Remote() && CurrentTimer->Remote() && strcmp(Timer->Remote(), CurrentTimer->Remote()) == 0)) CurrentItem = Item; } Sort(); @@ -1255,6 +1331,11 @@ eOSState cMenuTimers::OnOff(void) cTimer *Timer = GetTimer(); if (Timer) { Timer->OnOff(); + if (Timer->Remote()) { + cStringList Response; + if (!ExecSVDRPCommand(Timer->Remote(), cString::sprintf("MODT %d %s", Timer->Id(), *Timer->ToText(true)), &Response) || SVDRPCode(Response[0]) != 250) + Skins.Message(mtError, cString::sprintf(tr("Error while accessing timer %d@%s!"), Timer->Id(), Timer->Remote())); + } LOCK_SCHEDULES_READ; Timer->SetEventFromSchedule(Schedules); RefreshCurrent(); @@ -1272,7 +1353,6 @@ eOSState cMenuTimers::Edit(void) { if (HasSubMenu() || Count() == 0) return osContinue; - isyslog("editing timer %s", *GetTimer()->ToDescr()); return AddSubMenu(new cMenuEditTimer(GetTimer())); } @@ -1292,17 +1372,24 @@ eOSState cMenuTimers::Delete(void) if (Interface->Confirm(tr("Delete timer?"))) { if (Timer->Recording()) { if (Interface->Confirm(tr("Timer still recording - really delete?"))) { - Timer->Skip(); - cRecordControls::Process(Timers, time(NULL)); + if (!Timer->Remote()) { + Timer->Skip(); + cRecordControls::Process(Timers, time(NULL)); + } } else Timer = NULL; } if (Timer) { - isyslog("deleting timer %s", *Timer->ToDescr()); + if (Timer->Remote()) { + cStringList Response; + if (!ExecSVDRPCommand(Timer->Remote(), cString::sprintf("DELT %d", Timer->Id()), &Response) || SVDRPCode(Response[0]) != 250) + Skins.Message(mtError, cString::sprintf(tr("Error while accessing timer %d@%s!"), Timer->Id(), Timer->Remote())); + } Timers->Del(Timer); cOsdMenu::Del(Current()); Display(); + isyslog("deleted timer %s", *Timer->ToDescr()); } } } @@ -3925,6 +4012,7 @@ void cMenuSetupMisc::Set(void) Add(new cMenuEditStrItem( tr("Setup.Miscellaneous$SVDRP host name"), data.SVDRPHostName, sizeof(data.SVDRPHostName))); if (GetSVDRPServerNames(&svdrpServerNames)) { svdrpServerNames.Sort(true); + svdrpServerNames.Insert(strdup("")); Add(new cMenuEditStrlItem(tr("Setup.Miscellaneous$SVDRP default host"), data.SVDRPDefaultHost, sizeof(data.SVDRPDefaultHost), &svdrpServerNames)); } } diff --git a/menu.h b/menu.h index d4855edc..3f380840 100644 --- a/menu.h +++ b/menu.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 4.1 2015/08/31 13:34:12 kls Exp $ + * $Id: menu.h 4.2 2015/09/08 14:04:27 kls Exp $ */ #ifndef __MENU_H @@ -77,12 +77,15 @@ private: cTimer data; int channel; bool addIfConfirmed; + cStringList svdrpServerNames; + char remote[HOST_NAME_MAX]; cMenuEditStrItem *file; cMenuEditDateItem *day; cMenuEditDateItem *firstday; eOSState SetFolder(void); void SetFirstDayItem(void); void SetHelpKeys(void); + bool HandleRemoteModifications(cTimer *OldTimer, cTimer *NewTimer); public: cMenuEditTimer(cTimer *Timer, bool New = false); virtual ~cMenuEditTimer(); diff --git a/recording.c b/recording.c index 3f5cec7c..a847c7d1 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 4.3 2015/08/29 14:42:53 kls Exp $ + * $Id: recording.c 4.4 2015/09/09 10:21:58 kls Exp $ */ #include "recording.h" @@ -2018,7 +2018,7 @@ cMark::~cMark() cString cMark::ToText(void) { - return cString::sprintf("%s%s%s\n", *IndexToHMSF(position, true, framesPerSecond), Comment() ? " " : "", Comment() ? Comment() : ""); + return cString::sprintf("%s%s%s", *IndexToHMSF(position, true, framesPerSecond), Comment() ? " " : "", Comment() ? Comment() : ""); } bool cMark::Parse(const char *s) @@ -2037,7 +2037,7 @@ bool cMark::Parse(const char *s) bool cMark::Save(FILE *f) { - return fprintf(f, "%s", *ToText()) > 0; + return fprintf(f, "%s\n", *ToText()) > 0; } // --- cMarks ---------------------------------------------------------------- diff --git a/svdrp.c b/svdrp.c index 65be32ad..a57d58ca 100644 --- a/svdrp.c +++ b/svdrp.c @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 4.6 2015/09/08 11:08:06 kls Exp $ + * $Id: svdrp.c 4.7 2015/09/10 10:39:45 kls Exp $ */ #include "svdrp.h" @@ -512,7 +512,7 @@ public: cSVDRPClientHandler(int TcpPort, int UdpPort); virtual ~cSVDRPClientHandler(); void SendDiscover(const char *Address = NULL); - bool Execute(const char *ServerName, const char *Command, cStringList *Response); + bool Execute(const char *ServerName, const char *Command, cStringList *Response = NULL); bool GetServerNames(cStringList *ServerNames, eSvdrpFetchFlags FetchFlags = sffNone); bool TriggerFetchingTimers(const char *ServerName); }; @@ -1305,16 +1305,13 @@ void cSVDRPServer::CmdDELT(const char *Option) if (isnumber(Option)) { LOCK_TIMERS_WRITE; Timers->SetExplicitModify(); - cTimer *Timer = Timers->GetById(strtol(Option, NULL, 10)); - if (Timer && !Timer->Remote()) { - if (!Timer->Recording()) { - Timers->Del(Timer); - Timers->SetModified(); - isyslog("SVDRP < %s deleted timer %s", *connection, *Timer->ToDescr()); - Reply(250, "Timer \"%s\" deleted", Option); - } - else - Reply(550, "Timer \"%s\" is recording", Option); + if (cTimer *Timer = Timers->GetById(strtol(Option, NULL, 10))) { + if (Timer->Recording()) + Timer->Skip(); + Timers->Del(Timer); + Timers->SetModified(); + isyslog("SVDRP < %s deleted timer %s", *connection, *Timer->ToDescr()); + Reply(250, "Timer \"%s\" deleted", Option); } else Reply(501, "Timer \"%s\" not defined", Option); @@ -2566,22 +2563,10 @@ bool GetSVDRPServerNames(cStringList *ServerNames, eSvdrpFetchFlags FetchFlag) return false; } -// --- cSVDRPCommand --------------------------------------------------------- - -cSVDRPCommand::cSVDRPCommand(const char *ServerName, const char *Command) -{ - serverName = ServerName; - command = Command; -} - -cSVDRPCommand::~cSVDRPCommand() -{ -} - -bool cSVDRPCommand::Execute(void) +bool ExecSVDRPCommand(const char *ServerName, const char *Command, cStringList *Response) { cMutexLock MutexLock(&SVDRPHandlerMutex); if (SVDRPClientHandler) - return SVDRPClientHandler->Execute(serverName, command, &response); + return SVDRPClientHandler->Execute(ServerName, Command, Response); return false; } diff --git a/svdrp.h b/svdrp.h index 10c0c053..ba33fc27 100644 --- a/svdrp.h +++ b/svdrp.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: svdrp.h 4.4 2015/09/06 12:39:24 kls Exp $ + * $Id: svdrp.h 4.5 2015/09/09 09:44:12 kls Exp $ */ #ifndef __SVDRP_H @@ -12,46 +12,6 @@ #include "tools.h" -class cSVDRPCommand { -protected: - cString serverName; - cString command; - cStringList response; -public: - cSVDRPCommand(const char *ServerName, const char *Command); - ///< Sets up an SVDRP Command to be executed on the VDR with the given - ///< ServerName. A list of all available servers can be retrieved by - ///< calling GetSVDRPServerNames(). - ///< Command is one SVDRP command, followed by optional parameters, - ///< just as it can be given in a normal SVDRP connection. It doesn't - ///< need to be terminated with a newline. - virtual ~cSVDRPCommand(); - bool Execute(void); - ///< Sends the Command given in the constructor to the remote VDR - ///< and collects all of the response strings. - ///< Returns true if the data exchange was successful. Whether or - ///< not the actual SVDRP command was successful depends on the - ///< resulting strings from the remote VDR, which can be accessed - ///< by calling Response(). Execute() can be called any number of - ///< times. The list of response strings will be cleared before - ///< the command is actually executed. - const cStringList *Response(void) const { return &response; } - ///< Returns the list of strings the remote VDR has sent in response - ///< to the command. The response strings are exactly as received, - ///< with the leading three digit reply code and possible continuation - ///< line indicator ('-') in place. - const char *Response(int Index) { return (Index >= 0 && Index < response.Size()) ? response[Index] : NULL; } - ///< This is a convenience function for accessing the response strings. - ///< Returns the string at the given Index, or NULL if Index is out - ///< of range. - int Code(const char *s) { return s ? atoi(s) : 0; } - ///< Returns the value of the three digit reply code of the given - ///< response string. - const char *Value(const char *s) { return s && s[0] && s[1] && s[2] && s[3] ? s + 4 : NULL; } - ///< Returns the actual value of the given response string, skipping - ///< the three digit reply code and possible continuation line indicator. - }; - enum eSvdrpFetchFlags { sffNone = 0b0000, sffTimers = 0b0001, @@ -72,5 +32,21 @@ bool GetSVDRPServerNames(cStringList *ServerNames, eSvdrpFetchFlags FetchFlag = ///< client has this flag set will be returned, and the client's flag ///< will be cleared. ///< Returns true if the resulting list is not empty. +bool ExecSVDRPCommand(const char *ServerName, const char *Command, cStringList *Response = NULL); + ///< Sends the given SVDRP Command string to the remote VDR identified + ///< by ServerName and collects all of the response strings in Response. + ///< If no Response parameter is given, the response from command execution + ///< is ignored. + ///< Returns true if the data exchange was successful. Whether or + ///< not the actual SVDRP command was successful depends on the + ///< resulting strings from the remote VDR, which can be accessed + ///< through Response. If Response is given, it will be cleared before + ///< the command is actually executed. +inline int SVDRPCode(const char *s) { return s ? atoi(s) : 0; } + ///< Returns the value of the three digit reply code of the given + ///< SVDRP response string. +inline const char *SVDRPValue(const char *s) { return s && s[0] && s[1] && s[2] && s[3] ? s + 4 : NULL; } + ///< Returns the actual value of the given SVDRP response string, skipping + ///< the three digit reply code and possible continuation line indicator. #endif //__SVDRP_H diff --git a/timers.c b/timers.c index 77e9096d..7fd977e2 100644 --- a/timers.c +++ b/timers.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: timers.c 4.3 2015/09/08 10:01:02 kls Exp $ + * $Id: timers.c 4.4 2015/09/09 10:42:18 kls Exp $ */ #include "timers.h" @@ -33,7 +33,7 @@ cTimer::cTimer(bool Instant, bool Pause, const cChannel *Channel) flags = tfNone; *file = 0; aux = NULL; - remote = NULL; + remote = *Setup.SVDRPDefaultHost ? strdup(Setup.SVDRPDefaultHost) : NULL; event = NULL; if (Instant) SetFlags(tfActive | tfInstant); @@ -91,7 +91,7 @@ cTimer::cTimer(const cEvent *Event) flags = tfActive; *file = 0; aux = NULL; - remote = NULL; + remote = *Setup.SVDRPDefaultHost ? strdup(Setup.SVDRPDefaultHost) : NULL; event = NULL; if (Event->Vps() && Setup.UseVps) SetFlags(tfVps); @@ -185,7 +185,7 @@ int cTimer::Compare(const cListObject &ListObject) const cString cTimer::ToText(bool UseChannelID) const { strreplace(file, ':', '|'); - cString buffer = cString::sprintf("%u:%s:%s:%04d:%04d:%d:%d:%s:%s\n", flags, UseChannelID ? *Channel()->GetChannelID().ToString() : *itoa(Channel()->Number()), *PrintDay(day, weekdays, true), start, stop, priority, lifetime, file, aux ? aux : ""); + cString buffer = cString::sprintf("%u:%s:%s:%04d:%04d:%d:%d:%s:%s", flags, UseChannelID ? *Channel()->GetChannelID().ToString() : *itoa(Channel()->Number()), *PrintDay(day, weekdays, true), start, stop, priority, lifetime, file, aux ? aux : ""); strreplace(file, '|', ':'); return buffer; } @@ -355,7 +355,7 @@ bool cTimer::Parse(const char *s) bool cTimer::Save(FILE *f) { if (!Remote()) - return fprintf(f, "%s", *ToText(true)) > 0; + return fprintf(f, "%s\n", *ToText(true)) > 0; return true; } @@ -726,7 +726,7 @@ bool cTimers::Load(const char *FileName) Timers->SetExplicitModify(); if (timers.cConfig::Load(FileName)) { for (cTimer *ti = timers.First(); ti; ti = timers.Next(ti)) { - ti->SetId(++lastTimerId); + ti->SetId(NewTimerId()); ti->ClrFlags(tfRecording); Timers->SetModified(); } @@ -735,6 +735,11 @@ bool cTimers::Load(const char *FileName) return false; } +int cTimers::NewTimerId(void) +{ + return ++lastTimerId; // no need for locking, the caller must have a lock on the global Timers list +} + const cTimer *cTimers::GetById(int Id) const { for (const cTimer *ti = First(); ti; ti = Next(ti)) { @@ -824,7 +829,7 @@ cTimers *cTimers::GetTimersWrite(cStateKey &StateKey, int TimeoutMs) void cTimers::Add(cTimer *Timer, cTimer *After) { if (!Timer->Remote()) - Timer->SetId(++lastTimerId); + Timer->SetId(NewTimerId()); cConfig::Add(Timer, After); cStatus::MsgTimerChange(Timer, tcAdd); } @@ -882,13 +887,13 @@ bool cTimers::GetRemoteTimers(const char *ServerName) bool Result = false; if (ServerName) { Result = DelRemoteTimers(ServerName); - cSVDRPCommand Cmd(ServerName, "LSTT ID"); - if (Cmd.Execute()) { - const char *s; - for (int i = 0; s = Cmd.Response(i); i++) { - int Code = Cmd.Code(s); + cStringList Response; + if (ExecSVDRPCommand(ServerName, "LSTT ID", &Response)) { + for (int i = 0; i < Response.Size(); i++) { + const char *s = Response[i]; + int Code = SVDRPCode(s); if (Code == 250) { - if (const char *v = Cmd.Value(s)) { + if (const char *v = SVDRPValue(s)) { int Id = atoi(v); while (*v && *v != ' ') v++; // skip id @@ -939,8 +944,7 @@ bool cTimers::DelRemoteTimers(const char *ServerName) void cTimers::TriggerRemoteTimerPoll(const char *ServerName) { if (ServerName) { - cSVDRPCommand Cmd(ServerName, cString::sprintf("POLL %s TIMERS", Setup.SVDRPHostName)); - if (!Cmd.Execute()) + if (!ExecSVDRPCommand(ServerName, cString::sprintf("POLL %s TIMERS", Setup.SVDRPHostName))) esyslog("ERROR: can't send 'POLL %s TIMERS' to '%s'", Setup.SVDRPHostName, ServerName); } else { diff --git a/timers.h b/timers.h index 38eb9284..4222c104 100644 --- a/timers.h +++ b/timers.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: timers.h 4.2 2015/09/05 13:51:33 kls Exp $ + * $Id: timers.h 4.3 2015/09/09 10:40:24 kls Exp $ */ #ifndef __TIMERS_H @@ -67,6 +67,7 @@ public: time_t FirstDay(void) const { return weekdays ? day : 0; } const char *Aux(void) const { return aux; } const char *Remote(void) const { return remote; } + bool Local(void) const { return !remote; } // convenience time_t Deferred(void) const { return deferred; } cString ToText(bool UseChannelID = false) const; cString ToDescr(void) const; @@ -166,6 +167,7 @@ public: ///< StateKey.Remove(); ///< } static bool Load(const char *FileName); + static int NewTimerId(void); const cTimer *GetById(int Id) const; cTimer *GetById(int Id) { return const_cast(static_cast(this)->GetById(Id)); }; cTimer *GetTimer(cTimer *Timer);