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.
|
connections to keep them alive.
|
||||||
- The new function GetSVDRPServerNames() can be used to get a list of all VDRs
|
- The new function GetSVDRPServerNames() can be used to get a list of all VDRs
|
||||||
this VDR is connected to via SVDRP.
|
this VDR is connected to via SVDRP.
|
||||||
- The new class cSVDRPCommand can be used to execute an SVDRP command on one of
|
- The new function ExecSVDRPCommand() can be used to execute an SVDRP command on
|
||||||
the servers this VDR is connected to, and retrieve the result.
|
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
|
- 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.
|
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
|
- 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
|
".../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
|
in the same network. Peering is disabled by default and can be enabled by setting
|
||||||
"SVDRP peering" to "yes".
|
"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.
|
the name of the recording.
|
||||||
First day: The date of the first day when this timer shall start recording
|
First day: The date of the first day when this timer shall start recording
|
||||||
(only available for repeating timers).
|
(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",
|
A timer can also be programmed by pressing the "Red" key on the "Schedule",
|
||||||
"Now", "Next" or "Event" menus.
|
"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
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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"
|
#include "channels.h"
|
||||||
@ -554,9 +554,9 @@ cString cChannel::ToText(const cChannel *Channel)
|
|||||||
cString buffer;
|
cString buffer;
|
||||||
if (Channel->groupSep) {
|
if (Channel->groupSep) {
|
||||||
if (Channel->number)
|
if (Channel->number)
|
||||||
buffer = cString::sprintf(":@%d %s\n", Channel->number, FullName);
|
buffer = cString::sprintf(":@%d %s", Channel->number, FullName);
|
||||||
else
|
else
|
||||||
buffer = cString::sprintf(":%s\n", FullName);
|
buffer = cString::sprintf(":%s", FullName);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
char vpidbuf[32];
|
char vpidbuf[32];
|
||||||
@ -588,7 +588,7 @@ cString cChannel::ToText(const cChannel *Channel)
|
|||||||
q = caidbuf;
|
q = caidbuf;
|
||||||
q += IntArrayToString(q, Channel->caids, 16);
|
q += IntArrayToString(q, Channel->caids, 16);
|
||||||
*q = 0;
|
*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;
|
return buffer;
|
||||||
}
|
}
|
||||||
@ -806,7 +806,7 @@ bool cChannel::Parse(const char *s)
|
|||||||
|
|
||||||
bool cChannel::Save(FILE *f)
|
bool cChannel::Save(FILE *f)
|
||||||
{
|
{
|
||||||
return fprintf(f, "%s", *ToText()) > 0;
|
return fprintf(f, "%s\n", *ToText()) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- cChannelSorter --------------------------------------------------------
|
// --- cChannelSorter --------------------------------------------------------
|
||||||
|
96
menu.c
96
menu.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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"
|
#include "menu.h"
|
||||||
@ -999,6 +999,15 @@ cMenuEditTimer::cMenuEditTimer(cTimer *Timer, bool New)
|
|||||||
Add(new cMenuEditIntItem( tr("Lifetime"), &data.lifetime, 0, MAXLIFETIME));
|
Add(new cMenuEditIntItem( tr("Lifetime"), &data.lifetime, 0, MAXLIFETIME));
|
||||||
Add(file = new cMenuEditStrItem( tr("File"), data.file, sizeof(data.file)));
|
Add(file = new cMenuEditStrItem( tr("File"), data.file, sizeof(data.file)));
|
||||||
SetFirstDayItem();
|
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();
|
SetHelpKeys();
|
||||||
}
|
}
|
||||||
@ -1053,6 +1062,70 @@ eOSState cMenuEditTimer::SetFolder(void)
|
|||||||
return CloseSubMenu();
|
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 cMenuEditTimer::ProcessKey(eKeys Key)
|
||||||
{
|
{
|
||||||
eOSState state = cOsdMenu::ProcessKey(Key);
|
eOSState state = cOsdMenu::ProcessKey(Key);
|
||||||
@ -1074,6 +1147,9 @@ eOSState cMenuEditTimer::ProcessKey(eKeys Key)
|
|||||||
}
|
}
|
||||||
if (!*data.file)
|
if (!*data.file)
|
||||||
strcpy(data.file, data.Channel()->ShortName(true));
|
strcpy(data.file, data.Channel()->ShortName(true));
|
||||||
|
data.SetRemote(*remote ? remote : NULL);
|
||||||
|
if (!HandleRemoteModifications(timer, &data))
|
||||||
|
return osContinue;
|
||||||
*timer = data;
|
*timer = data;
|
||||||
if (addIfConfirmed) {
|
if (addIfConfirmed) {
|
||||||
Timers->Add(timer);
|
Timers->Add(timer);
|
||||||
@ -1215,7 +1291,7 @@ void cMenuTimers::Set(void)
|
|||||||
for (const cTimer *Timer = Timers->First(); Timer; Timer = Timers->Next(Timer)) {
|
for (const cTimer *Timer = Timers->First(); Timer; Timer = Timers->Next(Timer)) {
|
||||||
cMenuTimerItem *Item = new cMenuTimerItem(Timer);
|
cMenuTimerItem *Item = new cMenuTimerItem(Timer);
|
||||||
Add(Item);
|
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;
|
CurrentItem = Item;
|
||||||
}
|
}
|
||||||
Sort();
|
Sort();
|
||||||
@ -1255,6 +1331,11 @@ eOSState cMenuTimers::OnOff(void)
|
|||||||
cTimer *Timer = GetTimer();
|
cTimer *Timer = GetTimer();
|
||||||
if (Timer) {
|
if (Timer) {
|
||||||
Timer->OnOff();
|
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;
|
LOCK_SCHEDULES_READ;
|
||||||
Timer->SetEventFromSchedule(Schedules);
|
Timer->SetEventFromSchedule(Schedules);
|
||||||
RefreshCurrent();
|
RefreshCurrent();
|
||||||
@ -1272,7 +1353,6 @@ eOSState cMenuTimers::Edit(void)
|
|||||||
{
|
{
|
||||||
if (HasSubMenu() || Count() == 0)
|
if (HasSubMenu() || Count() == 0)
|
||||||
return osContinue;
|
return osContinue;
|
||||||
isyslog("editing timer %s", *GetTimer()->ToDescr());
|
|
||||||
return AddSubMenu(new cMenuEditTimer(GetTimer()));
|
return AddSubMenu(new cMenuEditTimer(GetTimer()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1292,17 +1372,24 @@ eOSState cMenuTimers::Delete(void)
|
|||||||
if (Interface->Confirm(tr("Delete timer?"))) {
|
if (Interface->Confirm(tr("Delete timer?"))) {
|
||||||
if (Timer->Recording()) {
|
if (Timer->Recording()) {
|
||||||
if (Interface->Confirm(tr("Timer still recording - really delete?"))) {
|
if (Interface->Confirm(tr("Timer still recording - really delete?"))) {
|
||||||
|
if (!Timer->Remote()) {
|
||||||
Timer->Skip();
|
Timer->Skip();
|
||||||
cRecordControls::Process(Timers, time(NULL));
|
cRecordControls::Process(Timers, time(NULL));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
Timer = NULL;
|
Timer = NULL;
|
||||||
}
|
}
|
||||||
if (Timer) {
|
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);
|
Timers->Del(Timer);
|
||||||
cOsdMenu::Del(Current());
|
cOsdMenu::Del(Current());
|
||||||
Display();
|
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)));
|
Add(new cMenuEditStrItem( tr("Setup.Miscellaneous$SVDRP host name"), data.SVDRPHostName, sizeof(data.SVDRPHostName)));
|
||||||
if (GetSVDRPServerNames(&svdrpServerNames)) {
|
if (GetSVDRPServerNames(&svdrpServerNames)) {
|
||||||
svdrpServerNames.Sort(true);
|
svdrpServerNames.Sort(true);
|
||||||
|
svdrpServerNames.Insert(strdup(""));
|
||||||
Add(new cMenuEditStrlItem(tr("Setup.Miscellaneous$SVDRP default host"), data.SVDRPDefaultHost, sizeof(data.SVDRPDefaultHost), &svdrpServerNames));
|
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
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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
|
#ifndef __MENU_H
|
||||||
@ -77,12 +77,15 @@ private:
|
|||||||
cTimer data;
|
cTimer data;
|
||||||
int channel;
|
int channel;
|
||||||
bool addIfConfirmed;
|
bool addIfConfirmed;
|
||||||
|
cStringList svdrpServerNames;
|
||||||
|
char remote[HOST_NAME_MAX];
|
||||||
cMenuEditStrItem *file;
|
cMenuEditStrItem *file;
|
||||||
cMenuEditDateItem *day;
|
cMenuEditDateItem *day;
|
||||||
cMenuEditDateItem *firstday;
|
cMenuEditDateItem *firstday;
|
||||||
eOSState SetFolder(void);
|
eOSState SetFolder(void);
|
||||||
void SetFirstDayItem(void);
|
void SetFirstDayItem(void);
|
||||||
void SetHelpKeys(void);
|
void SetHelpKeys(void);
|
||||||
|
bool HandleRemoteModifications(cTimer *OldTimer, cTimer *NewTimer);
|
||||||
public:
|
public:
|
||||||
cMenuEditTimer(cTimer *Timer, bool New = false);
|
cMenuEditTimer(cTimer *Timer, bool New = false);
|
||||||
virtual ~cMenuEditTimer();
|
virtual ~cMenuEditTimer();
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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"
|
#include "recording.h"
|
||||||
@ -2018,7 +2018,7 @@ cMark::~cMark()
|
|||||||
|
|
||||||
cString cMark::ToText(void)
|
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)
|
bool cMark::Parse(const char *s)
|
||||||
@ -2037,7 +2037,7 @@ bool cMark::Parse(const char *s)
|
|||||||
|
|
||||||
bool cMark::Save(FILE *f)
|
bool cMark::Save(FILE *f)
|
||||||
{
|
{
|
||||||
return fprintf(f, "%s", *ToText()) > 0;
|
return fprintf(f, "%s\n", *ToText()) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- cMarks ----------------------------------------------------------------
|
// --- cMarks ----------------------------------------------------------------
|
||||||
|
29
svdrp.c
29
svdrp.c
@ -10,7 +10,7 @@
|
|||||||
* and interact with the Video Disk Recorder - or write a full featured
|
* and interact with the Video Disk Recorder - or write a full featured
|
||||||
* graphical interface that sits on top of an SVDRP connection.
|
* 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"
|
#include "svdrp.h"
|
||||||
@ -512,7 +512,7 @@ public:
|
|||||||
cSVDRPClientHandler(int TcpPort, int UdpPort);
|
cSVDRPClientHandler(int TcpPort, int UdpPort);
|
||||||
virtual ~cSVDRPClientHandler();
|
virtual ~cSVDRPClientHandler();
|
||||||
void SendDiscover(const char *Address = NULL);
|
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 GetServerNames(cStringList *ServerNames, eSvdrpFetchFlags FetchFlags = sffNone);
|
||||||
bool TriggerFetchingTimers(const char *ServerName);
|
bool TriggerFetchingTimers(const char *ServerName);
|
||||||
};
|
};
|
||||||
@ -1305,17 +1305,14 @@ void cSVDRPServer::CmdDELT(const char *Option)
|
|||||||
if (isnumber(Option)) {
|
if (isnumber(Option)) {
|
||||||
LOCK_TIMERS_WRITE;
|
LOCK_TIMERS_WRITE;
|
||||||
Timers->SetExplicitModify();
|
Timers->SetExplicitModify();
|
||||||
cTimer *Timer = Timers->GetById(strtol(Option, NULL, 10));
|
if (cTimer *Timer = Timers->GetById(strtol(Option, NULL, 10))) {
|
||||||
if (Timer && !Timer->Remote()) {
|
if (Timer->Recording())
|
||||||
if (!Timer->Recording()) {
|
Timer->Skip();
|
||||||
Timers->Del(Timer);
|
Timers->Del(Timer);
|
||||||
Timers->SetModified();
|
Timers->SetModified();
|
||||||
isyslog("SVDRP < %s deleted timer %s", *connection, *Timer->ToDescr());
|
isyslog("SVDRP < %s deleted timer %s", *connection, *Timer->ToDescr());
|
||||||
Reply(250, "Timer \"%s\" deleted", Option);
|
Reply(250, "Timer \"%s\" deleted", Option);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
Reply(550, "Timer \"%s\" is recording", Option);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
Reply(501, "Timer \"%s\" not defined", Option);
|
Reply(501, "Timer \"%s\" not defined", Option);
|
||||||
}
|
}
|
||||||
@ -2566,22 +2563,10 @@ bool GetSVDRPServerNames(cStringList *ServerNames, eSvdrpFetchFlags FetchFlag)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- cSVDRPCommand ---------------------------------------------------------
|
bool ExecSVDRPCommand(const char *ServerName, const char *Command, cStringList *Response)
|
||||||
|
|
||||||
cSVDRPCommand::cSVDRPCommand(const char *ServerName, const char *Command)
|
|
||||||
{
|
|
||||||
serverName = ServerName;
|
|
||||||
command = Command;
|
|
||||||
}
|
|
||||||
|
|
||||||
cSVDRPCommand::~cSVDRPCommand()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cSVDRPCommand::Execute(void)
|
|
||||||
{
|
{
|
||||||
cMutexLock MutexLock(&SVDRPHandlerMutex);
|
cMutexLock MutexLock(&SVDRPHandlerMutex);
|
||||||
if (SVDRPClientHandler)
|
if (SVDRPClientHandler)
|
||||||
return SVDRPClientHandler->Execute(serverName, command, &response);
|
return SVDRPClientHandler->Execute(ServerName, Command, Response);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
58
svdrp.h
58
svdrp.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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
|
#ifndef __SVDRP_H
|
||||||
@ -12,46 +12,6 @@
|
|||||||
|
|
||||||
#include "tools.h"
|
#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 {
|
enum eSvdrpFetchFlags {
|
||||||
sffNone = 0b0000,
|
sffNone = 0b0000,
|
||||||
sffTimers = 0b0001,
|
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
|
///< client has this flag set will be returned, and the client's flag
|
||||||
///< will be cleared.
|
///< will be cleared.
|
||||||
///< Returns true if the resulting list is not empty.
|
///< 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
|
#endif //__SVDRP_H
|
||||||
|
34
timers.c
34
timers.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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"
|
#include "timers.h"
|
||||||
@ -33,7 +33,7 @@ cTimer::cTimer(bool Instant, bool Pause, const cChannel *Channel)
|
|||||||
flags = tfNone;
|
flags = tfNone;
|
||||||
*file = 0;
|
*file = 0;
|
||||||
aux = NULL;
|
aux = NULL;
|
||||||
remote = NULL;
|
remote = *Setup.SVDRPDefaultHost ? strdup(Setup.SVDRPDefaultHost) : NULL;
|
||||||
event = NULL;
|
event = NULL;
|
||||||
if (Instant)
|
if (Instant)
|
||||||
SetFlags(tfActive | tfInstant);
|
SetFlags(tfActive | tfInstant);
|
||||||
@ -91,7 +91,7 @@ cTimer::cTimer(const cEvent *Event)
|
|||||||
flags = tfActive;
|
flags = tfActive;
|
||||||
*file = 0;
|
*file = 0;
|
||||||
aux = NULL;
|
aux = NULL;
|
||||||
remote = NULL;
|
remote = *Setup.SVDRPDefaultHost ? strdup(Setup.SVDRPDefaultHost) : NULL;
|
||||||
event = NULL;
|
event = NULL;
|
||||||
if (Event->Vps() && Setup.UseVps)
|
if (Event->Vps() && Setup.UseVps)
|
||||||
SetFlags(tfVps);
|
SetFlags(tfVps);
|
||||||
@ -185,7 +185,7 @@ int cTimer::Compare(const cListObject &ListObject) const
|
|||||||
cString cTimer::ToText(bool UseChannelID) const
|
cString cTimer::ToText(bool UseChannelID) const
|
||||||
{
|
{
|
||||||
strreplace(file, ':', '|');
|
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, '|', ':');
|
strreplace(file, '|', ':');
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
@ -355,7 +355,7 @@ bool cTimer::Parse(const char *s)
|
|||||||
bool cTimer::Save(FILE *f)
|
bool cTimer::Save(FILE *f)
|
||||||
{
|
{
|
||||||
if (!Remote())
|
if (!Remote())
|
||||||
return fprintf(f, "%s", *ToText(true)) > 0;
|
return fprintf(f, "%s\n", *ToText(true)) > 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -726,7 +726,7 @@ bool cTimers::Load(const char *FileName)
|
|||||||
Timers->SetExplicitModify();
|
Timers->SetExplicitModify();
|
||||||
if (timers.cConfig<cTimer>::Load(FileName)) {
|
if (timers.cConfig<cTimer>::Load(FileName)) {
|
||||||
for (cTimer *ti = timers.First(); ti; ti = timers.Next(ti)) {
|
for (cTimer *ti = timers.First(); ti; ti = timers.Next(ti)) {
|
||||||
ti->SetId(++lastTimerId);
|
ti->SetId(NewTimerId());
|
||||||
ti->ClrFlags(tfRecording);
|
ti->ClrFlags(tfRecording);
|
||||||
Timers->SetModified();
|
Timers->SetModified();
|
||||||
}
|
}
|
||||||
@ -735,6 +735,11 @@ bool cTimers::Load(const char *FileName)
|
|||||||
return false;
|
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
|
const cTimer *cTimers::GetById(int Id) const
|
||||||
{
|
{
|
||||||
for (const cTimer *ti = First(); ti; ti = Next(ti)) {
|
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)
|
void cTimers::Add(cTimer *Timer, cTimer *After)
|
||||||
{
|
{
|
||||||
if (!Timer->Remote())
|
if (!Timer->Remote())
|
||||||
Timer->SetId(++lastTimerId);
|
Timer->SetId(NewTimerId());
|
||||||
cConfig<cTimer>::Add(Timer, After);
|
cConfig<cTimer>::Add(Timer, After);
|
||||||
cStatus::MsgTimerChange(Timer, tcAdd);
|
cStatus::MsgTimerChange(Timer, tcAdd);
|
||||||
}
|
}
|
||||||
@ -882,13 +887,13 @@ bool cTimers::GetRemoteTimers(const char *ServerName)
|
|||||||
bool Result = false;
|
bool Result = false;
|
||||||
if (ServerName) {
|
if (ServerName) {
|
||||||
Result = DelRemoteTimers(ServerName);
|
Result = DelRemoteTimers(ServerName);
|
||||||
cSVDRPCommand Cmd(ServerName, "LSTT ID");
|
cStringList Response;
|
||||||
if (Cmd.Execute()) {
|
if (ExecSVDRPCommand(ServerName, "LSTT ID", &Response)) {
|
||||||
const char *s;
|
for (int i = 0; i < Response.Size(); i++) {
|
||||||
for (int i = 0; s = Cmd.Response(i); i++) {
|
const char *s = Response[i];
|
||||||
int Code = Cmd.Code(s);
|
int Code = SVDRPCode(s);
|
||||||
if (Code == 250) {
|
if (Code == 250) {
|
||||||
if (const char *v = Cmd.Value(s)) {
|
if (const char *v = SVDRPValue(s)) {
|
||||||
int Id = atoi(v);
|
int Id = atoi(v);
|
||||||
while (*v && *v != ' ')
|
while (*v && *v != ' ')
|
||||||
v++; // skip id
|
v++; // skip id
|
||||||
@ -939,8 +944,7 @@ bool cTimers::DelRemoteTimers(const char *ServerName)
|
|||||||
void cTimers::TriggerRemoteTimerPoll(const char *ServerName)
|
void cTimers::TriggerRemoteTimerPoll(const char *ServerName)
|
||||||
{
|
{
|
||||||
if (ServerName) {
|
if (ServerName) {
|
||||||
cSVDRPCommand Cmd(ServerName, cString::sprintf("POLL %s TIMERS", Setup.SVDRPHostName));
|
if (!ExecSVDRPCommand(ServerName, cString::sprintf("POLL %s TIMERS", Setup.SVDRPHostName)))
|
||||||
if (!Cmd.Execute())
|
|
||||||
esyslog("ERROR: can't send 'POLL %s TIMERS' to '%s'", Setup.SVDRPHostName, ServerName);
|
esyslog("ERROR: can't send 'POLL %s TIMERS' to '%s'", Setup.SVDRPHostName, ServerName);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
4
timers.h
4
timers.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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
|
#ifndef __TIMERS_H
|
||||||
@ -67,6 +67,7 @@ public:
|
|||||||
time_t FirstDay(void) const { return weekdays ? day : 0; }
|
time_t FirstDay(void) const { return weekdays ? day : 0; }
|
||||||
const char *Aux(void) const { return aux; }
|
const char *Aux(void) const { return aux; }
|
||||||
const char *Remote(void) const { return remote; }
|
const char *Remote(void) const { return remote; }
|
||||||
|
bool Local(void) const { return !remote; } // convenience
|
||||||
time_t Deferred(void) const { return deferred; }
|
time_t Deferred(void) const { return deferred; }
|
||||||
cString ToText(bool UseChannelID = false) const;
|
cString ToText(bool UseChannelID = false) const;
|
||||||
cString ToDescr(void) const;
|
cString ToDescr(void) const;
|
||||||
@ -166,6 +167,7 @@ public:
|
|||||||
///< StateKey.Remove();
|
///< StateKey.Remove();
|
||||||
///< }
|
///< }
|
||||||
static bool Load(const char *FileName);
|
static bool Load(const char *FileName);
|
||||||
|
static int NewTimerId(void);
|
||||||
const cTimer *GetById(int Id) const;
|
const cTimer *GetById(int Id) const;
|
||||||
cTimer *GetById(int Id) { return const_cast<cTimer *>(static_cast<const cTimers *>(this)->GetById(Id)); };
|
cTimer *GetById(int Id) { return const_cast<cTimer *>(static_cast<const cTimers *>(this)->GetById(Id)); };
|
||||||
cTimer *GetTimer(cTimer *Timer);
|
cTimer *GetTimer(cTimer *Timer);
|
||||||
|
Loading…
Reference in New Issue
Block a user