summaryrefslogtreecommitdiff
path: root/client/remote.c
diff options
context:
space:
mode:
authorlordjaxom <lordjaxom>2004-12-30 22:43:55 +0000
committerlordjaxom <lordjaxom>2004-12-30 22:43:55 +0000
commit302fa2e67276bd0674e81e2a9a01b9e91dd45d8c (patch)
treea454884a16e0ffa48b5ce3e4ce1a66eb874a9de0 /client/remote.c
downloadvdr-plugin-streamdev-302fa2e67276bd0674e81e2a9a01b9e91dd45d8c.tar.gz
vdr-plugin-streamdev-302fa2e67276bd0674e81e2a9a01b9e91dd45d8c.tar.bz2
Initial revision
Diffstat (limited to 'client/remote.c')
-rw-r--r--client/remote.c475
1 files changed, 475 insertions, 0 deletions
diff --git a/client/remote.c b/client/remote.c
new file mode 100644
index 0000000..4cc7cfe
--- /dev/null
+++ b/client/remote.c
@@ -0,0 +1,475 @@
+/*
+ * $Id: remote.c,v 1.1 2004/12/30 22:44:02 lordjaxom Exp $
+ */
+
+#include "client/remote.h"
+#include "client/device.h"
+#include "common.h"
+
+cRemoteTimers RemoteTimers;
+
+// --- cRemoteRecording ------------------------------------------------------
+
+cRemoteRecording::cRemoteRecording(const char *Text) {
+ m_IsValid = false;
+ m_Index = -1;
+ m_IsNew = false;
+ m_TitleBuffer = NULL;
+
+ char *ptr;
+ char *timestr;
+ int idx;
+
+ Dprintf("text: %s\n", Text);
+
+ m_Index = strtoul(Text, &ptr, 10);
+ Dprintf("index: %d\n", m_Index);
+ if (*ptr == '\0' || *++ptr == '\0' ) return;
+ timestr = ptr;
+ while (*ptr != '\0' && !isspace(*ptr)) ++ptr;
+ if (*ptr == '\0' || *++ptr == '\0') return;
+ while (*ptr != '\0' && *ptr != '*' && !isspace(*ptr)) ++ptr;
+ if (*ptr == '*') m_IsNew = true;
+ Dprintf("new: %d\n", m_IsNew);
+ *(ptr++) = '\0';
+ m_StartTime = timestr;
+ idx = -1;
+ while ((idx = m_StartTime.Find(' ', idx + 1)) != -1) m_StartTime[idx] = '\t';
+ Dprintf("m_Start: %s\n", (const char*)m_StartTime);
+ if (*ptr == 0) return;
+ if (isspace(*ptr)) ++ptr;
+ if (*ptr == 0) return;
+ m_Name = ptr;
+ Dprintf("file: %s\n", (const char*)m_Name);
+ m_IsValid = true;
+}
+
+cRemoteRecording::~cRemoteRecording(void) {
+}
+
+bool cRemoteRecording::operator==(const cRemoteRecording &Recording) {
+ return m_IsValid == Recording.m_IsValid
+ && m_Index == Recording.m_Index
+ && m_StartTime == Recording.m_StartTime
+ && m_Name == Recording.m_Name;
+}
+
+void cRemoteRecording::ParseInfo(const char *Text) {
+ m_Summary = strreplace(strdup(Text), '|', '\n');
+}
+
+const char *cRemoteRecording::Title(char Delimiter, bool NewIndicator,
+ int Level) {
+ char New = NewIndicator && IsNew() ? '*' : ' ';
+
+ if (m_TitleBuffer != NULL) {
+ free(m_TitleBuffer);
+ m_TitleBuffer = NULL;
+ }
+
+ if (Level < 0 || Level == HierarchyLevels()) {
+ char *s;
+ const char *t;
+ if (Level > 0 && (t = strrchr(m_Name, '~')) != NULL)
+ t++;
+ else
+ t = (const char*)m_Name;
+
+ asprintf(&m_TitleBuffer, "%s%c%c%s", (const char*)m_StartTime, New,
+ Delimiter, t);
+ // let's not display a trailing '~':
+ stripspace(m_TitleBuffer);
+ s = &m_TitleBuffer[strlen(m_TitleBuffer) - 1];
+ if (*s == '~')
+ *s = 0;
+ } else if (Level < HierarchyLevels()) {
+ const char *s = m_Name;
+ const char *p = s;
+ while (*++s) {
+ if (*s == '~') {
+ if (Level--)
+ p = s + 1;
+ else
+ break;
+ }
+ }
+ m_TitleBuffer = MALLOC(char, s - p + 3);
+ *m_TitleBuffer = Delimiter;
+ *(m_TitleBuffer + 1) = Delimiter;
+ strn0cpy(m_TitleBuffer + 2, p, s - p + 1);
+ } else
+ return "";
+ return m_TitleBuffer;
+}
+
+int cRemoteRecording::HierarchyLevels(void)
+{
+ const char *s = m_Name;
+ int level = 0;
+ while (*++s) {
+ if (*s == '~') ++level;
+ }
+ return level;
+}
+
+// --- cRemoteRecordings -----------------------------------------------------
+
+bool cRemoteRecordings::Load(void) {
+ Clear();
+ return ClientSocket.LoadRecordings(*this);
+}
+
+cRemoteRecording *cRemoteRecordings::GetByName(const char *Name) {
+ for (cRemoteRecording *r = First(); r; r = Next(r))
+ if (strcmp(r->Name(), Name) == 0)
+ return r;
+ return NULL;
+}
+
+// --- cRemoteTimer ----------------------------------------------------------
+
+cRemoteTimer::cRemoteTimer(const char *Text) {
+ m_IsValid = false;
+ m_Index = -1;
+ m_Active = -1;
+ m_Day = -1;
+ m_Start = -1;
+ m_Stop = -1;
+ m_StartTime = 0;
+ m_StopTime = 0;
+ m_Priority = -1;
+ m_Lifetime = -1;
+ m_File[0] = '\0';
+ m_FirstDay = 0;
+ m_Buffer = NULL;
+ m_Channel = NULL;
+
+ char *tmpbuf;
+ char *ptr;
+
+ Dprintf("text: %s\n", Text);
+
+ m_Index = strtoul(Text, &ptr, 10);
+ Dprintf("index: %d\n", m_Index);
+ if (*ptr == '\0' || *++ptr == '\0') return;
+ m_Active = strtoul(ptr, &ptr, 10);
+ Dprintf("m_Active: %d\n", m_Active);
+ if (*ptr == '\0' || *++ptr == '\0') return;
+
+ tmpbuf = ptr;
+ while (*ptr != '\0' && *ptr != ':') ++ptr;
+ if (*ptr == '\0') return;
+ *(ptr++)= '\0';
+ if (isnumber(tmpbuf))
+ m_Channel = Channels.GetByNumber(strtoul(tmpbuf, NULL, 10));
+ else
+ m_Channel = Channels.GetByChannelID(tChannelID::FromString(tmpbuf));
+ Dprintf("channel no.: %d\n", m_Channel->Number());
+
+ tmpbuf = ptr;
+ while (*ptr != '\0' && *ptr != ':') ++ptr;
+ if (*ptr == '\0') return;
+ *(ptr++) = '\0';
+ m_Day = ParseDay(tmpbuf, &m_FirstDay);
+ Dprintf("Day: %d\n", m_Day);
+ m_Start = strtoul(ptr, &ptr, 10);
+ Dprintf("Start: %d\n", m_Start);
+ if (*ptr == '\0' || *++ptr == '\0') return;
+ m_Stop = strtoul(ptr, &ptr, 10);
+ Dprintf("Stop: %d\n", m_Stop);
+ if (*ptr == '\0' || *++ptr == '\0') return;
+ m_Priority = strtoul(ptr, &ptr, 10);
+ Dprintf("Prio: %d\n", m_Priority);
+ if (*ptr == '\0' || *++ptr == '\0') return;
+ m_Lifetime = strtoul(ptr, &ptr, 10);
+ Dprintf("Lifetime: %d\n", m_Lifetime);
+ if (*ptr == '\0' || *++ptr == '\0') return;
+ tmpbuf = ptr;
+ while (*ptr != '\0' && *ptr != ':') ++ptr;
+ if (*ptr == '\0') return;
+ *(ptr++) = '\0';
+ strncpy(m_File, tmpbuf, MaxFileName);
+ Dprintf("file: %s\n", m_File);
+ if (*ptr != '\0') m_Summary = ptr;
+ Dprintf("summary: %s\n", (const char*)m_Summary);
+ m_IsValid = true;
+}
+
+#if VDRVERSNUM < 10300
+cRemoteTimer::cRemoteTimer(const cEventInfo *EventInfo) {
+ time_t tstart = EventInfo->GetTime();
+ time_t tstop = tstart + EventInfo->GetDuration() + Setup.MarginStop * 60;
+ tstart -= Setup.MarginStart * 60;
+ struct tm tm_r;
+ struct tm *time = localtime_r(&tstart, &tm_r);
+ const char *title = EventInfo->GetTitle();
+ cChannel *channel = Channels.GetByChannelID(EventInfo->GetChannelID(), true);
+#else
+cRemoteTimer::cRemoteTimer(const cEvent *Event) {
+ time_t tstart = Event->StartTime();
+ time_t tstop = tstart + Event->Duration() + Setup.MarginStop * 60;
+ tstart -= Setup.MarginStart * 60;
+ struct tm tm_r;
+ struct tm *time = localtime_r(&tstart, &tm_r);
+ const char *title = Event->Title();
+ cChannel *channel = Channels.GetByChannelID(Event->ChannelID(), true);
+#endif
+
+ m_IsValid = true;
+ m_Index = -1;
+ m_Active = true;
+ m_Day = time->tm_mday;
+ m_Start = time->tm_hour * 100 + time->tm_min;
+ time = localtime_r(&tstop, &tm_r);
+ m_Stop = time->tm_hour * 100 + time->tm_min;
+ m_StartTime = 0;
+ m_StopTime = 0;
+ if (m_Stop >= 2400) m_Stop -= 2400;
+ m_Priority = Setup.DefaultPriority;
+ m_Lifetime = Setup.DefaultLifetime;
+ m_File[0] = '\0';
+ if (!isempty(title))
+ strn0cpy(m_File, title, sizeof(m_File));
+ m_FirstDay = 0;
+ m_Channel = channel;
+}
+
+cRemoteTimer::cRemoteTimer(void) {
+ time_t t = time(NULL);
+ struct tm tm_r;
+ struct tm *now = localtime_r(&t, &tm_r);
+
+ m_IsValid = true;
+ m_Index = -1;
+ m_Active = -1;
+ m_Day = now->tm_mday;
+ m_Start = now->tm_hour * 100 + now->tm_min;
+ m_Stop = now->tm_hour * 60 + now->tm_min + Setup.InstantRecordTime;
+ m_Stop = (m_Stop / 60) * 100 + (m_Stop % 60);
+ if (m_Stop >= 2400) m_Stop -= 2400;
+ m_StartTime = 0;
+ m_StopTime = 0;
+ m_Priority = Setup.DefaultPriority;
+ m_Lifetime = Setup.DefaultLifetime;
+ m_File[0] = '\0';
+ m_FirstDay = 0;
+ m_Buffer = NULL;
+ m_Channel = Channels.GetByNumber(cDevice::CurrentChannel());
+}
+
+cRemoteTimer::~cRemoteTimer() {
+ if (m_Buffer != NULL) free(m_Buffer);
+}
+
+cRemoteTimer &cRemoteTimer::operator=(const cRemoteTimer &Timer) {
+ Dprintf("\n\n\n\nOPÜERATHVBDÖLJVG\n\n\n");
+ m_IsValid = Timer.m_IsValid;
+ m_Index = Timer.m_Index;
+ m_Active = Timer.m_Active;
+ m_Day = Timer.m_Day;
+ m_Start = Timer.m_Start;
+ m_Stop = Timer.m_Stop;
+ m_Priority = Timer.m_Priority;
+ m_Lifetime = Timer.m_Lifetime;
+ m_FirstDay = Timer.m_FirstDay;
+ m_Channel = Timer.m_Channel;
+ m_Summary = Timer.m_Summary;
+ return *this;
+}
+
+bool cRemoteTimer::operator==(const cRemoteTimer &Timer) {
+ return m_IsValid == Timer.m_IsValid
+ && m_Index == Timer.m_Index
+ && m_Active == Timer.m_Active
+ && m_Day == Timer.m_Day
+ && m_Start == Timer.m_Start
+ && m_Stop == Timer.m_Stop
+ && m_Priority == Timer.m_Priority
+ && m_Lifetime == Timer.m_Lifetime
+ && m_FirstDay == Timer.m_FirstDay
+ && m_Channel == Timer.m_Channel
+ && strcmp(m_File, Timer.m_File) == 0
+ && m_Summary == Timer.m_Summary;
+}
+
+int cRemoteTimer::ParseDay(const char *s, time_t *FirstDay) {
+ char *tail;
+ int d = strtol(s, &tail, 10);
+ if (FirstDay)
+ *FirstDay = 0;
+ if (tail && *tail) {
+ d = 0;
+ if (tail == s) {
+ const char *first = strchr(s, '@');
+ int l = first ? first - s : strlen(s);
+ if (l == 7) {
+ for (const char *p = s + 6; p >= s; p--) {
+ d <<= 1;
+ d |= (*p != '-');
+ }
+ d |= 0x80000000;
+ }
+ if (FirstDay && first) {
+ ++first;
+ if (strlen(first) == 10) {
+ struct tm tm_r;
+ if (3 == sscanf(first, "%d-%d-%d", &tm_r.tm_year, &tm_r.tm_mon, &tm_r.tm_mday)) {
+ tm_r.tm_year -= 1900;
+ tm_r.tm_mon--;
+ tm_r.tm_hour = tm_r.tm_min = tm_r.tm_sec = 0;
+ tm_r.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting
+ *FirstDay = mktime(&tm_r);
+ }
+ }
+ else
+ d = 0;
+ }
+ }
+ }
+ else if (d < 1 || d > 31)
+ d = 0;
+ return d;
+}
+
+const char *cRemoteTimer::PrintDay(int d, time_t FirstDay) {
+#define DAYBUFFERSIZE 32
+ static char buffer[DAYBUFFERSIZE];
+ if ((d & 0x80000000) != 0) {
+ char *b = buffer;
+ const char *w = tr("MTWTFSS");
+ while (*w) {
+ *b++ = (d & 1) ? *w : '-';
+ d >>= 1;
+ w++;
+ }
+ if (FirstDay) {
+ struct tm tm_r;
+ localtime_r(&FirstDay, &tm_r);
+ b += strftime(b, DAYBUFFERSIZE - (b - buffer), "@%Y-%m-%d", &tm_r);
+ }
+ *b = 0;
+ }
+ else
+ sprintf(buffer, "%d", d);
+ return buffer;
+}
+
+const char *cRemoteTimer::PrintFirstDay(void) const {
+ if (m_FirstDay) {
+ const char *s = PrintDay(m_Day, m_FirstDay);
+ if (strlen(s) == 18)
+ return s + 8;
+ }
+ return ""; // not NULL, so the caller can always use the result
+}
+
+void cRemoteTimer::OnOff(void) {
+ if (IsSingleEvent())
+ m_Active = !m_Active;
+ else if (m_FirstDay) {
+ m_FirstDay = 0;
+ m_Active = false;
+ }
+ else if (m_Active)
+ Skip();
+ else
+ m_Active = true;
+ Matches(); // refresh m_Start and end time
+}
+
+time_t cRemoteTimer::SetTime(time_t t, int SecondsFromMidnight) {
+ struct tm tm_r;
+ tm tm = *localtime_r(&t, &tm_r);
+ tm.tm_hour = SecondsFromMidnight / 3600;
+ tm.tm_min = (SecondsFromMidnight % 3600) / 60;
+ tm.tm_sec = SecondsFromMidnight % 60;
+ tm.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting
+ return mktime(&tm);
+}
+
+bool cRemoteTimer::Matches(time_t t) {
+ m_StartTime = m_StopTime = 0;
+ if (t == 0)
+ t = time(NULL);
+
+ int begin = TimeToInt(m_Start); // seconds from midnight
+ int length = TimeToInt(m_Stop) - begin;
+ if (length < 0)
+ length += SECSINDAY;
+
+ int DaysToCheck = IsSingleEvent() ? 61 : 7; // 61 to handle months with 31/30/31
+ for (int i = -1; i <= DaysToCheck; i++) {
+ time_t t0 = IncDay(t, i);
+ if (DayMatches(t0)) {
+ time_t a = SetTime(t0, begin);
+ time_t b = a + length;
+ if ((!m_FirstDay || a >= m_FirstDay) && t <= b) {
+ m_StartTime = a;
+ m_StopTime = b;
+ break;
+ }
+ }
+ }
+ if (!m_StartTime)
+ m_StartTime = m_FirstDay; // just to have something that's more than a week in the future
+ else if (t > m_StartTime || t > m_FirstDay + SECSINDAY + 3600) // +3600 in case of DST change
+ m_FirstDay = 0;
+ return m_Active && m_StartTime <= t && t < m_StopTime; // must m_Stop *before* m_StopTime to allow adjacent timers
+}
+
+bool cRemoteTimer::DayMatches(time_t t) {
+ return IsSingleEvent()
+ ? GetMDay(t) == m_Day
+ : (m_Day & (1 << GetWDay(t))) != 0;
+}
+
+int cRemoteTimer::GetMDay(time_t t)
+{
+ struct tm tm_r;
+ return localtime_r(&t, &tm_r)->tm_mday;
+}
+
+int cRemoteTimer::GetWDay(time_t t)
+{
+ struct tm tm_r;
+ int weekday = localtime_r(&t, &tm_r)->tm_wday;
+ return weekday == 0 ? 6 : weekday - 1; // we start with monday==0!
+}
+
+time_t cRemoteTimer::IncDay(time_t t, int Days) {
+ struct tm tm_r;
+ tm tm = *localtime_r(&t, &tm_r);
+ tm.tm_mday += Days; // now tm_mday may be out of its valid range
+ int h = tm.tm_hour; // save original hour to compensate for DST change
+ tm.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting
+ t = mktime(&tm); // normalize all values
+ tm.tm_hour = h; // compensate for DST change
+ return mktime(&tm); // calculate final result
+}
+
+const char *cRemoteTimer::ToText(void) {
+ char *summary = NULL;
+
+ if (m_Buffer != NULL) free(m_Buffer);
+
+ strreplace(m_File, ':', '|');
+ if (!m_Summary.IsNull())
+ summary = strreplace(strdup(m_Summary), ':', '|');
+
+ asprintf(&m_Buffer, "%d:%s:%s:%04d:%04d:%d:%d:%s:%s", m_Active,
+ Channel()->GetChannelID().ToString(), PrintDay(m_Day, m_FirstDay),
+ m_Start, m_Stop, m_Priority, m_Lifetime, m_File, summary ? summary : "");
+
+ if (summary != NULL)
+ free(summary);
+ strreplace(m_File, '|', ':');
+ return m_Buffer;
+}
+
+// --- cRemoteTimers ---------------------------------------------------------
+
+bool cRemoteTimers::Load(void) {
+ Clear();
+ return ClientSocket.LoadTimers(*this);
+}
+