summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HISTORY4
-rw-r--r--svdrp.c21
-rw-r--r--timers.c121
-rw-r--r--timers.h6
-rw-r--r--tools.c14
-rw-r--r--tools.h18
6 files changed, 144 insertions, 40 deletions
diff --git a/HISTORY b/HISTORY
index 468e58ea..cdb632c6 100644
--- a/HISTORY
+++ b/HISTORY
@@ -9162,7 +9162,7 @@ Video Disk Recorder Revision History
a subdirectory.
- SVDRP peering can now be limited to the default SVDRP host (see MANUAL for details).
-2018-02-27: Version 2.3.9
+2018-02-28: Version 2.3.9
- Updated the Italian OSD texts (thanks to Diego Pierotto).
- Updated the Finnish OSD texts (thanks to Rolf Ahrenberg).
@@ -9286,3 +9286,5 @@ Video Disk Recorder Revision History
- Moved handling remote timers into cSVDRPClientHandler::ProcessConnections().
- Combined Start/StopSVDRPServer/ClientHandler() into Start/StopSVDRPHandler().
- Updated the Polish OSD texts (thanks to Tomasz Maciej Nowak).
+- When remote timers are fetched from a peer VDR, we no longer blindly delete and re-add
+ them, but rather compare them and make only the minimum necessary changes.
diff --git a/svdrp.c b/svdrp.c
index 6e3a58a2..93ead5eb 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.30 2018/02/26 15:42:15 kls Exp $
+ * $Id: svdrp.c 4.31 2018/02/28 10:04:00 kls Exp $
*/
#include "svdrp.h"
@@ -483,8 +483,23 @@ bool cSVDRPClient::HasFetchFlag(eSvdrpFetchFlags Flag)
bool cSVDRPClient::GetRemoteTimers(cStringList &Response)
{
- if (HasFetchFlag(sffTimers))
- return Execute("LSTT ID", &Response);
+ if (HasFetchFlag(sffTimers)) {
+ if (Execute("LSTT ID", &Response)) {
+ for (int i = 0; i < Response.Size(); i++) {
+ char *s = Response[i];
+ int Code = SVDRPCode(s);
+ if (Code == 250)
+ strshift(s, 4);
+ else {
+ if (Code != 550)
+ esyslog("ERROR: %s: %s", ServerName(), s);
+ return false;
+ }
+ }
+ Response.SortNumerically();
+ return true;
+ }
+ }
return false;
}
diff --git a/timers.c b/timers.c
index 9e4c4856..bc4dbbfa 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.15 2018/02/25 13:05:03 kls Exp $
+ * $Id: timers.c 4.16 2018/02/28 10:05:52 kls Exp $
*/
#include "timers.h"
@@ -900,45 +900,102 @@ bool cTimers::DeleteExpired(void)
bool cTimers::StoreRemoteTimers(const char *ServerName, const cStringList *RemoteTimers)
{
- //TODO handle only new/deleted/modified timers?
bool Result = false;
- // Delete old remote timers:
- cTimer *Timer = First();
- while (Timer) {
- cTimer *t = Next(Timer);
- if (Timer->Remote() && (!ServerName || strcmp(Timer->Remote(), ServerName) == 0)) {
- Del(Timer);
- Result = true;
+ if (!ServerName || !RemoteTimers || RemoteTimers->Size() == 0) {
+ // Remove remote timers from this list:
+ cTimer *Timer = First();
+ while (Timer) {
+ cTimer *t = Next(Timer);
+ if (Timer->Remote() && (!ServerName || strcmp(Timer->Remote(), ServerName) == 0)) {
+ Del(Timer);
+ Result = true;
+ }
+ Timer = t;
}
- Timer = t;
- }
- // Add new remote timers:
- if (ServerName && RemoteTimers) {
- for (int i = 0; i < RemoteTimers->Size(); i++) {
- const char *s = (*RemoteTimers)[i];
- int Code = SVDRPCode(s);
- if (Code == 250) {
- if (const char *v = SVDRPValue(s)) {
- int Id = atoi(v);
- while (*v && *v != ' ')
- v++; // skip id
- cTimer *Timer = new cTimer;
- if (Timer->Parse(v)) {
- Timer->SetRemote(ServerName);
- Timer->SetId(Id);
- Add(Timer);
+ return Result;
+ }
+ // Collect all locally stored remote timers from ServerName:
+ cStringList tl;
+ for (cTimer *ti = First(); ti; ti = Next(ti)) {
+ if (ti->Remote() && strcmp(ti->Remote(), ServerName) == 0)
+ tl.Append(strdup(cString::sprintf("%d %s", ti->Id(), *ti->ToText(true))));
+ }
+ tl.SortNumerically(); // RemoteTimers is also sorted numerically!
+ // Compare the two lists and react accordingly:
+ int il = 0; // index into the local ("left") list of remote timers
+ int ir = 0; // index into the remote ("right") list of timers
+ int sl = tl.Size();
+ int sr = RemoteTimers->Size();
+ for (;;) {
+ int AddTimer = 0;
+ int DelTimer = 0;
+ if (il < sl) { // still have left entries
+ int nl = atoi(tl[il]);
+ if (ir < sr) { // still have right entries
+ // Compare timers:
+ int nr = atoi((*RemoteTimers)[ir]);
+ if (nl == nr) // same timer id
+ AddTimer = DelTimer = nl;
+ else if (nl < nr) // left entry not in right list
+ DelTimer = nl;
+ else // right entry not in left list
+ AddTimer = nr;
+ }
+ else // processed all right entries
+ DelTimer = nl;
+ }
+ else if (ir < sr) // still have right entries
+ AddTimer = atoi((*RemoteTimers)[ir]);
+ else // processed all left and right entries
+ break;
+ if (AddTimer && DelTimer) {
+ if (strcmp(tl[il], (*RemoteTimers)[ir]) != 0) {
+ // Overwrite timer:
+ char *v = (*RemoteTimers)[ir];
+ while (*v && *v != ' ')
+ v++; // skip id
+ if (cTimer *l = GetById(DelTimer, ServerName)) {
+ cTimer r;
+ if (r.Parse(v)) {
+ r.SetRemote(ServerName);
+ r.SetId(AddTimer);
+ *l = r;
Result = true;
}
- else {
+ else
esyslog("ERROR: %s: error in timer settings: %s", ServerName, v);
- delete Timer;
- }
}
}
- else if (Code != 550)
- esyslog("ERROR: %s: %s", ServerName, s);
+ else // identical timer, nothing to do
+ ;
+ il++;
+ ir++;
}
- }
+ else if (AddTimer) {
+ char *v = (*RemoteTimers)[ir];
+ while (*v && *v != ' ')
+ v++; // skip id
+ cTimer *Timer = new cTimer;
+ if (Timer->Parse(v)) {
+ Timer->SetRemote(ServerName);
+ Timer->SetId(AddTimer);
+ Add(Timer);
+ Result = true;
+ }
+ else {
+ esyslog("ERROR: %s: error in timer settings: %s", ServerName, v);
+ delete Timer;
+ }
+ ir++;
+ }
+ else if (DelTimer) {
+ if (cTimer *t = GetById(DelTimer, ServerName)) {
+ Del(t);
+ Result = true;
+ }
+ il++;
+ }
+ }
return Result;
}
diff --git a/timers.h b/timers.h
index 3146fce5..93d5a447 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.10 2018/02/25 12:54:55 kls Exp $
+ * $Id: timers.h 4.11 2018/02/27 13:57:26 kls Exp $
*/
#ifndef __TIMERS_H
@@ -190,7 +190,9 @@ public:
///< this list. If no ServerName is given, all remote timers from all peer machines
///< will be removed from this list. If no RemoteTimers are given, only the remote
///< timers from ServerName will be removed from this list.
- ///< Returns true if any remote timers have been added or deleted
+ ///< The given list of RemoteTimers must be sorted numerically (by a call to its
+ ///< SortNumerically() function).
+ ///< Returns true if any remote timers have been added, deleted or modified.
};
bool HandleRemoteTimerModifications(cTimer *NewTimer, cTimer *OldTimer = NULL, cString *Msg = NULL);
diff --git a/tools.c b/tools.c
index ac2f9eb2..28e03cdc 100644
--- a/tools.c
+++ b/tools.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: tools.c 4.8 2017/06/25 11:45:39 kls Exp $
+ * $Id: tools.c 4.9 2018/02/27 10:09:21 kls Exp $
*/
#include "tools.h"
@@ -296,6 +296,18 @@ cString strgetval(const char *s, const char *name, char d)
return NULL;
}
+char *strshift(char *s, int n)
+{
+ if (s && n > 0) {
+ int l = strlen(s);
+ if (n < l)
+ memmove(s, s + n, l - n + 1); // we also copy the terminating 0!
+ else
+ *s = 0;
+ }
+ return s;
+}
+
bool startswith(const char *s, const char *p)
{
while (*p) {
diff --git a/tools.h b/tools.h
index aaba602f..ffbd6825 100644
--- a/tools.h
+++ b/tools.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: tools.h 4.13 2017/06/25 11:45:38 kls Exp $
+ * $Id: tools.h 4.14 2018/02/28 10:06:47 kls Exp $
*/
#ifndef __TOOLS_H
@@ -226,6 +226,12 @@ cString strgetval(const char *s, const char *name, char d = '=');
///< If an other delimiter shall be used (like, e.g., ':'), it can be given
///< as the third parameter.
///< If name occurs more than once in s, only the first occurrence is taken.
+char *strshift(char *s, int n);
+ ///< Shifts the given string to the left by the given number of bytes, thus
+ ///< removing the first n bytes from s.
+ ///< If n is greater than the length of s, the resulting string will be empty.
+ ///< If n is <= 0 s will be unchanged.
+ ///< Returns s.
bool startswith(const char *s, const char *p);
bool endswith(const char *s, const char *p);
bool isempty(const char *s);
@@ -781,6 +787,12 @@ inline int CompareStringsIgnoreCase(const void *a, const void *b)
return strcasecmp(*(const char **)a, *(const char **)b);
}
+inline int CompareStringsNumerically(const void *a, const void *b)
+{
+ int d = atoi(*(const char **)a) - atoi(*(const char **)b);
+ return d ? d : CompareStrings(a, b);
+}
+
class cStringList : public cVector<char *> {
public:
cStringList(int Allocated = 10): cVector<char *>(Allocated) {}
@@ -793,6 +805,10 @@ public:
else
cVector<char *>::Sort(CompareStrings);
}
+ void SortNumerically(void)
+ {
+ cVector<char *>::Sort(CompareStringsNumerically);
+ }
virtual void Clear(void);
};