summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HISTORY5
-rw-r--r--svdrp.c74
-rw-r--r--timers.c29
-rw-r--r--timers.h8
4 files changed, 77 insertions, 39 deletions
diff --git a/HISTORY b/HISTORY
index bacc5604..e22377f3 100644
--- a/HISTORY
+++ b/HISTORY
@@ -8784,3 +8784,8 @@ Video Disk Recorder Revision History
communication printed to the console for debugging.
- Added a missing 'const' to cReceiver::Receive(), to protect the given Data from
being modified.
+- The SVDRP commands that deal with timers (DELT, LSTT, MODT, NEWT, NEXT and UPDT)
+ as well as any log messages that refer to timers, now use a unique id for each
+ timer, which remains valid as long as this instance of VDR is running. This means
+ that timers are no longer continuously numbered from 1 to N in LSTT. There may be
+ gaps in the sequence, in case timers have been deleted.
diff --git a/svdrp.c b/svdrp.c
index 8d7fce7d..28813ccb 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.3 2015/09/01 10:34:34 kls Exp $
+ * $Id: svdrp.c 4.4 2015/09/06 09:14:53 kls Exp $
*/
#include "svdrp.h"
@@ -1226,7 +1226,7 @@ void cSVDRPServer::CmdDELC(const char *Option)
Channels->SetExplicitModify();
if (cChannel *Channel = Channels->GetByNumber(strtol(Option, NULL, 10))) {
if (const cTimer *Timer = Timers->UsesChannel(Channel)) {
- Reply(550, "Channel \"%s\" is in use by timer %d", Option, Timer->Index() + 1);
+ Reply(550, "Channel \"%s\" is in use by timer %s", Option, *Timer->ToDescr());
return;
}
int CurrentChannelNr = cDevice::CurrentChannel();
@@ -1265,7 +1265,7 @@ static cString RecordingInUseMessage(int Reason, const char *RecordingId, cRecor
{
cRecordControl *rc;
if ((Reason & ruTimer) != 0 && (rc = cRecordControls::GetRecordControl(Recording->FileName())) != NULL)
- return cString::sprintf("Recording \"%s\" is in use by timer %d", RecordingId, rc->Timer()->Index() + 1);
+ return cString::sprintf("Recording \"%s\" is in use by timer %d", RecordingId, rc->Timer()->Id());
else if ((Reason & ruReplay) != 0)
return cString::sprintf("Recording \"%s\" is being replayed", RecordingId);
else if ((Reason & ruCut) != 0)
@@ -1312,12 +1312,12 @@ void cSVDRPServer::CmdDELT(const char *Option)
if (isnumber(Option)) {
LOCK_TIMERS_WRITE;
Timers->SetExplicitModify();
- cTimer *Timer = Timers->Get(strtol(Option, NULL, 10) - 1);
+ cTimer *Timer = Timers->GetById(strtol(Option, NULL, 10));
if (Timer && !Timer->Remote()) {
if (!Timer->Recording()) {
- isyslog("SVDRP < %s deleting timer %s", *connection, *Timer->ToDescr());
Timers->Del(Timer);
Timers->SetModified();
+ isyslog("SVDRP < %s deleted timer %s", *connection, *Timer->ToDescr());
Reply(250, "Timer \"%s\" deleted", Option);
}
else
@@ -1745,8 +1745,8 @@ void cSVDRPServer::CmdLSTR(const char *Option)
void cSVDRPServer::CmdLSTT(const char *Option)
{
- int Number = 0;
- bool Id = false;
+ int Id = 0;
+ bool UseChannelId = false;
if (*Option) {
char buf[strlen(Option) + 1];
strcpy(buf, Option);
@@ -1755,9 +1755,9 @@ void cSVDRPServer::CmdLSTT(const char *Option)
char *p = strtok_r(buf, delim, &strtok_next);
while (p) {
if (isnumber(p))
- Number = strtol(p, NULL, 10);
+ Id = strtol(p, NULL, 10);
else if (strcasecmp(p, "ID") == 0)
- Id = true;
+ UseChannelId = true;
else {
Reply(501, "Unknown option: \"%s\"", p);
return;
@@ -1766,11 +1766,11 @@ void cSVDRPServer::CmdLSTT(const char *Option)
}
}
LOCK_TIMERS_READ;
- if (Number) {
+ if (Id) {
for (const cTimer *Timer = Timers->First(); Timer; Timer = Timers->Next(Timer)) {
if (!Timer->Remote()) {
- if (Timer->Index() + 1 == Number) {
- Reply(250, "%d %s", Timer->Index() + 1, *Timer->ToText(Id));
+ if (Timer->Id() == Id) {
+ Reply(250, "%d %s", Timer->Id(), *Timer->ToText(UseChannelId));
return;
}
}
@@ -1779,15 +1779,19 @@ void cSVDRPServer::CmdLSTT(const char *Option)
return;
}
else {
- cVector<const cTimer *> LocalTimers;
- for (const cTimer *Timer = Timers->First(); Timer; Timer = Timers->Next(Timer)) {
- if (!Timer->Remote())
- LocalTimers.Append(Timer);
- }
- if (LocalTimers.Size()) {
- for (int i = 0; i < LocalTimers.Size(); i++) {
- const cTimer *Timer = LocalTimers[i];
- Reply(i < LocalTimers.Size() - 1 ? -250 : 250, "%d %s", Timer->Index() + 1, *Timer->ToText(Id));
+ const cTimer *LastLocalTimer = Timers->Last();
+ while (LastLocalTimer) {
+ if (LastLocalTimer->Remote())
+ LastLocalTimer = Timers->Prev(LastLocalTimer);
+ else
+ break;
+ }
+ if (LastLocalTimer) {
+ for (const cTimer *Timer = Timers->First(); Timer; Timer = Timers->Next(Timer)) {
+ if (!Timer->Remote())
+ Reply(Timer != LastLocalTimer ? -250 : 250, "%d %s", Timer->Id(), *Timer->ToText(UseChannelId));
+ if (Timer == LastLocalTimer)
+ break;
}
return;
}
@@ -1846,12 +1850,12 @@ void cSVDRPServer::CmdMODT(const char *Option)
{
if (*Option) {
char *tail;
- int n = strtol(Option, &tail, 10);
+ int Id = strtol(Option, &tail, 10);
if (tail && tail != Option) {
tail = skipspace(tail);
LOCK_TIMERS_WRITE;
Timers->SetExplicitModify();
- if (cTimer *Timer = Timers->Get(n - 1)) {
+ if (cTimer *Timer = Timers->GetById(Id)) {
cTimer t = *Timer;
if (strcasecmp(tail, "ON") == 0)
t.SetFlags(tfActive);
@@ -1863,11 +1867,11 @@ void cSVDRPServer::CmdMODT(const char *Option)
}
*Timer = t;
Timers->SetModified();
- isyslog("SVDRP < %s timer %s modified (%s)", *connection, *Timer->ToDescr(), Timer->HasFlags(tfActive) ? "active" : "inactive");
- Reply(250, "%d %s", Timer->Index() + 1, *Timer->ToText());
+ isyslog("SVDRP < %s modified timer %s (%s)", *connection, *Timer->ToDescr(), Timer->HasFlags(tfActive) ? "active" : "inactive");
+ Reply(250, "%d %s", Timer->Id(), *Timer->ToText());
}
else
- Reply(501, "Timer \"%d\" not defined", n);
+ Reply(501, "Timer \"%d\" not defined", Id);
}
else
Reply(501, "Error in timer number");
@@ -2007,8 +2011,8 @@ void cSVDRPServer::CmdNEWT(const char *Option)
if (Timer->Parse(Option)) {
LOCK_TIMERS_WRITE;
Timers->Add(Timer);
- isyslog("SVDRP < %s timer %s added", *connection, *Timer->ToDescr());
- Reply(250, "%d %s", Timer->Index() + 1, *Timer->ToText());
+ isyslog("SVDRP < %s added timer %s", *connection, *Timer->ToDescr());
+ Reply(250, "%d %s", Timer->Id(), *Timer->ToText());
return;
}
else
@@ -2024,13 +2028,13 @@ void cSVDRPServer::CmdNEXT(const char *Option)
LOCK_TIMERS_READ;
if (const cTimer *t = Timers->GetNextActiveTimer()) {
time_t Start = t->StartTime();
- int Number = t->Index() + 1;
+ int Id = t->Id();
if (!*Option)
- Reply(250, "%d %s", Number, *TimeToString(Start));
+ Reply(250, "%d %s", Id, *TimeToString(Start));
else if (strcasecmp(Option, "ABS") == 0)
- Reply(250, "%d %ld", Number, Start);
+ Reply(250, "%d %ld", Id, Start);
else if (strcasecmp(Option, "REL") == 0)
- Reply(250, "%d %ld", Number, Start - time(NULL));
+ Reply(250, "%d %ld", Id, Start - time(NULL));
else
Reply(501, "Unknown option: \"%s\"", Option);
}
@@ -2261,13 +2265,13 @@ void cSVDRPServer::CmdUPDT(const char *Option)
t->Parse(Option);
delete Timer;
Timer = t;
- isyslog("SVDRP < %s timer %s updated", *connection, *Timer->ToDescr());
+ isyslog("SVDRP < %s updated timer %s", *connection, *Timer->ToDescr());
}
else {
Timers->Add(Timer);
- isyslog("SVDRP < %s timer %s added", *connection, *Timer->ToDescr());
+ isyslog("SVDRP < %s added timer %s", *connection, *Timer->ToDescr());
}
- Reply(250, "%d %s", Timer->Index() + 1, *Timer->ToText());
+ Reply(250, "%d %s", Timer->Id(), *Timer->ToText());
return;
}
else
diff --git a/timers.c b/timers.c
index e124a1d5..0e5075fc 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.1 2015/08/31 10:45:13 kls Exp $
+ * $Id: timers.c 4.2 2015/09/05 14:42:50 kls Exp $
*/
#include "timers.h"
@@ -25,6 +25,7 @@
cTimer::cTimer(bool Instant, bool Pause, const cChannel *Channel)
{
+ id = 0;
startTime = stopTime = 0;
scheduleState = -1;
deferred = 0;
@@ -82,6 +83,7 @@ cTimer::cTimer(bool Instant, bool Pause, const cChannel *Channel)
cTimer::cTimer(const cEvent *Event)
{
+ id = 0;
startTime = stopTime = 0;
scheduleState = -1;
deferred = 0;
@@ -139,6 +141,7 @@ cTimer::~cTimer()
cTimer& cTimer::operator= (const cTimer &Timer)
{
if (&Timer != this) {
+ id = Timer.id;
uint OldFlags = flags & tfRecording;
startTime = Timer.startTime;
stopTime = Timer.stopTime;
@@ -189,7 +192,7 @@ cString cTimer::ToText(bool UseChannelID) const
cString cTimer::ToDescr(void) const
{
- return cString::sprintf("%d%s%s (%d %04d-%04d %s'%s')", Index() + 1, remote ? "@" : "", remote ? remote : "", Channel()->Number(), start, stop, HasFlags(tfVps) ? "VPS " : "", file);
+ return cString::sprintf("%d%s%s (%d %04d-%04d %s'%s')", Id(), remote ? "@" : "", remote ? remote : "", Channel()->Number(), start, stop, HasFlags(tfVps) ? "VPS " : "", file);
}
int cTimer::TimeToInt(int t)
@@ -522,6 +525,11 @@ time_t cTimer::StopTime(void) const
#define EPGLIMITBEFORE (1 * 3600) // Time in seconds before a timer's start time and
#define EPGLIMITAFTER (1 * 3600) // after its stop time within which EPG events will be taken into consideration.
+void cTimer::SetId(int Id)
+{
+ id = Id;
+}
+
bool cTimer::SetEventFromSchedule(const cSchedules *Schedules)
{
const cSchedule *Schedule = Schedules->GetSchedule(Channel());
@@ -704,6 +712,7 @@ void cTimer::OnOff(void)
// --- cTimers ---------------------------------------------------------------
cTimers cTimers::timers;
+int cTimers::lastTimerId = 0;
cTimers::cTimers(void)
:cConfig<cTimer>("Timers")
@@ -717,6 +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->ClrFlags(tfRecording);
Timers->SetModified();
}
@@ -725,6 +735,15 @@ bool cTimers::Load(const char *FileName)
return false;
}
+const cTimer *cTimers::GetById(int Id) const
+{
+ for (const cTimer *ti = First(); ti; ti = Next(ti)) {
+ if (!ti->Remote() && ti->Id() == Id)
+ return ti;
+ }
+ return NULL;
+}
+
cTimer *cTimers::GetTimer(cTimer *Timer)
{
for (cTimer *ti = First(); ti; ti = Next(ti)) {
@@ -804,6 +823,8 @@ cTimers *cTimers::GetTimersWrite(cStateKey &StateKey, int TimeoutMs)
void cTimers::Add(cTimer *Timer, cTimer *After)
{
+ if (!Timer->Remote())
+ Timer->SetId(++lastTimerId);
cConfig<cTimer>::Add(Timer, After);
cStatus::MsgTimerChange(Timer, tcAdd);
}
@@ -868,11 +889,13 @@ bool cTimers::GetRemoteTimers(const char *ServerName)
int Code = Cmd.Code(s);
if (Code == 250) {
if (const char *v = Cmd.Value(s)) {
+ int Id = atoi(v);
while (*v && *v != ' ')
- v++; // skip number
+ v++; // skip id
cTimer *Timer = new cTimer;
if (Timer->Parse(v)) {
Timer->SetRemote(ServerName);
+ Timer->SetId(Id);
Add(Timer);
Result = true;
}
diff --git a/timers.h b/timers.h
index 88a06624..38eb9284 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.1 2015/08/31 10:42:53 kls Exp $
+ * $Id: timers.h 4.2 2015/09/05 13:51:33 kls Exp $
*/
#ifndef __TIMERS_H
@@ -27,6 +27,7 @@ enum eTimerMatch { tmNone, tmPartial, tmFull };
class cTimer : public cListObject {
friend class cMenuEditTimer;
private:
+ int id;
mutable time_t startTime, stopTime;
int scheduleState;
mutable time_t deferred; ///< Matches(time_t, ...) will return false if the current time is before this value
@@ -50,6 +51,7 @@ public:
virtual ~cTimer();
cTimer& operator= (const cTimer &Timer);
virtual int Compare(const cListObject &ListObject) const;
+ int Id(void) const { return id; }
bool Recording(void) const { return HasFlags(tfRecording); }
bool Pending(void) const { return pending; }
bool InVpsMargin(void) const { return inVpsMargin; }
@@ -83,6 +85,7 @@ public:
bool Expired(void) const;
time_t StartTime(void) const;
time_t StopTime(void) const;
+ void SetId(int Id);
bool SetEventFromSchedule(const cSchedules *Schedules);
bool SetEvent(const cEvent *Event);
void SetRecording(bool Recording);
@@ -112,6 +115,7 @@ public:
class cTimers : public cConfig<cTimer> {
private:
static cTimers timers;
+ static int lastTimerId;
time_t lastDeleteExpired;
public:
cTimers(void);
@@ -162,6 +166,8 @@ public:
///< StateKey.Remove();
///< }
static bool Load(const char *FileName);
+ 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);
const cTimer *GetMatch(time_t t) const;
cTimer *GetMatch(time_t t) { return const_cast<cTimer *>(static_cast<const cTimers *>(this)->GetMatch(t)); };