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:
parent
4e3325b7f7
commit
bc0de5dbc5
16
HISTORY
16
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.
|
||||
|
3
MANUAL
3
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.
|
||||
|
10
channels.c
10
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 --------------------------------------------------------
|
||||
|
100
menu.c
100
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));
|
||||
}
|
||||
}
|
||||
|
5
menu.h
5
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();
|
||||
|
@ -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
37
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;
|
||||
}
|
||||
|
58
svdrp.h
58
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
|
||||
|
34
timers.c
34
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<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 {
|
||||
|
4
timers.h
4
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<cTimer *>(static_cast<const cTimers *>(this)->GetById(Id)); };
|
||||
cTimer *GetTimer(cTimer *Timer);
|
||||
|
Loading…
Reference in New Issue
Block a user