1
0
mirror of https://github.com/VDR4Arch/vdr.git synced 2023-10-10 13:36:52 +02:00

Implemented full handling of remote timers

This commit is contained in:
Klaus Schmidinger 2015-09-10 10:39:45 +02:00
parent 4e3325b7f7
commit bc0de5dbc5
10 changed files with 173 additions and 100 deletions

16
HISTORY
View File

@ -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.

3
MANUAL
View File

@ -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.

View File

@ -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 --------------------------------------------------------

100
menu.c
View File

@ -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));
}
}

5
menu.h
View File

@ -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();

View File

@ -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 ----------------------------------------------------------------

37
svdrp.c
View File

@ -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;
}

58
svdrp.h
View File

@ -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

View File

@ -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<cTimer>::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<cTimer>::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 {

View File

@ -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<cTimer *>(static_cast<const cTimers *>(this)->GetById(Id)); };
cTimer *GetTimer(cTimer *Timer);