diff options
author | lordjaxom <lordjaxom> | 2004-12-30 22:43:55 +0000 |
---|---|---|
committer | lordjaxom <lordjaxom> | 2004-12-30 22:43:55 +0000 |
commit | 302fa2e67276bd0674e81e2a9a01b9e91dd45d8c (patch) | |
tree | a454884a16e0ffa48b5ce3e4ce1a66eb874a9de0 /client/remote.c | |
download | vdr-plugin-streamdev-302fa2e67276bd0674e81e2a9a01b9e91dd45d8c.tar.gz vdr-plugin-streamdev-302fa2e67276bd0674e81e2a9a01b9e91dd45d8c.tar.bz2 |
Initial revision
Diffstat (limited to 'client/remote.c')
-rw-r--r-- | client/remote.c | 475 |
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); +} + |