45 time_t t = time(NULL);
47 struct tm *now = localtime_r(&t, &tm_r);
50 start = now->tm_hour * 100 + now->tm_min;
57 if (
const cEvent *
Event = Schedule->GetPresentEvent()) {
68 tstart -= MarginStart;
72 struct tm *time = localtime_r(&tstart, &tm_r);
73 start = time->tm_hour * 100 + time->tm_min;
74 time = localtime_r(&tstop, &tm_r);
75 stop = time->tm_hour * 100 + time->tm_min;
98 if (strcmp(Pattern,
"*") == 0) {
113 nt.
Set(
const_cast<char *
>(Pattern + strlen(Pattern) - 1));
114 if (AnchorBegin && AnchorEnd) {
115 if (strcmp(Title, Pattern) == 0) {
125 else if (AnchorBegin) {
126 if (strstr(Title, Pattern) == Title) {
132 *After =
cString(Title + strlen(Pattern));
136 else if (AnchorEnd) {
139 *Before =
cString(Title, Title + strlen(Title) - strlen(Pattern));
147 else if (
const char *p = strstr(Title, Pattern)) {
153 *After =
cString(p + strlen(Pattern));
162 if (!Pattern || !Title || !File)
167 if (
MatchPattern(Pattern, Title, &Before, &Match, &After)) {
168 char *Result = strdup(File);
207 tstart -= MarginStart;
211 struct tm *time = localtime_r(&tstart, &tm_r);
214 start = time->tm_hour * 100 + time->tm_min;
215 time = localtime_r(&tstop, &tm_r);
216 stop = time->tm_hour * 100 + time->tm_min;
241 event->DecNumTimers();
248 if (&Timer !=
this) {
269 aux = Timer.
aux ? strdup(Timer.
aux) : NULL;
273 event->DecNumTimers();
288 MarginStart =
max(0,
min(MarginStart, e->Duration() - 60));
290 MarginStop =
max(0,
min(MarginStop, e->Duration() - 60));
323 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, *
PatternAndFile(),
aux ?
aux :
"");
336 return (t / 100 * 60 + t % 100) * 60;
353 const char *a = strchr(s,
'@');
354 const char *d = a ? a + 1 : isdigit(*s) ? s : NULL;
356 if (strlen(d) == 10) {
358 if (3 == sscanf(d,
"%d-%d-%d", &tm_r.tm_year, &tm_r.tm_mon, &tm_r.tm_mday)) {
359 tm_r.tm_year -= 1900;
361 tm_r.tm_hour = tm_r.tm_min = tm_r.tm_sec = 0;
371 int day = strtol(d, &tail, 10);
374 time_t t = time(NULL);
375 int DaysToCheck = 61;
376 for (
int i = -1; i <= DaysToCheck; i++) {
385 if (a || !isdigit(*s)) {
386 if ((a && a - s == 7) || strlen(s) == 7) {
387 for (
const char *p = s + 6; p >= s; p--) {
400#define DAYBUFFERSIZE 64
405 const char *w =
trNOOP(
"MTWTFSS");
406 if (!SingleByteChars)
411 for (
int i = 0; i < sl; i++)
425 localtime_r(&
Day, &tm_r);
426 b += strftime(b,
DAYBUFFERSIZE - (b - buffer),
"%Y-%m-%d", &tm_r);
444 char *channelbuffer = NULL;
445 char *daybuffer = NULL;
446 char *filebuffer = NULL;
457 while (l2 > 0 && isspace(s[l2 - 1]))
459 if (s[l2 - 1] ==
':') {
460 s2 =
MALLOC(
char, l2 + 3);
461 strcat(
strn0cpy(s2, s, l2 + 1),
" \n");
465 if (8 <= sscanf(s,
"%u :%m[^:]:%m[^:]:%d :%d :%d :%d :%m[^:\n]:%m[^\n]", &
flags, &channelbuffer, &daybuffer, &
start, &
stop, &
priority, &
lifetime, &filebuffer, &
aux)) {
472 char *fb = filebuffer;
474 if (
char *p = strchr(fb,
'}')) {
487 channel = Channels->GetByNumber(atoi(channelbuffer));
491 esyslog(
"ERROR: channel %s not defined", channelbuffer);
505 return fprintf(f,
"%s\n", *
ToText(
true)) > 0;
517 return localtime_r(&t, &tm_r)->tm_mday;
523 int weekday = localtime_r(&t, &tm_r)->tm_wday;
524 return weekday == 0 ? 6 : weekday - 1;
535 tm tm = *localtime_r(&t, &tm_r);
547 tm tm = *localtime_r(&t, &tm_r);
548 tm.tm_hour = SecondsFromMidnight / 3600;
549 tm.tm_min = (SecondsFromMidnight % 3600) / 60;
550 tm.tm_sec = SecondsFromMidnight % 60;
566#define EITPRESENTFOLLOWINGRATE 10
567#define EITPRESENTFOLLOWINGGRACE 60
577 int length = end - begin;
588 for (
int i = -1; i <= 7; i++) {
595 if ((!
day || a >=
day) && t < b) {
619 if (Margin || !Directly) {
629 bool running =
event->IsRunning(
true);
640 return event->IsRunning(
true);
654 if (!Margin && !Directly) {
668#define FULLMATCH 1000
724#define EXPIRELATENCY 60
732 return ExpireTime <= time(NULL);
755 return event->StartTime();
766 return event->EndTime();
773#define EPGLIMITBEFORE (1 * 3600)
774#define EPGLIMITAFTER (1 * 3600)
796 bool TimersSpawned =
false;
800 time_t Now = time(NULL);
806 if (!Timer && e->EndTime() > Now) {
808 TimersSpawned =
true;
820 if (e->StartTime() <= Limit) {
823 TimersSpawned =
true;
837 return TimersSpawned;
851 tstart -= MarginStart;
860 struct tm *time = localtime_r(&tstart, &tm_r);
862 SetStart(time->tm_hour * 100 + time->tm_min);
863 time = localtime_r(&tstop, &tm_r);
864 SetStop(time->tm_hour * 100 + time->tm_min);
883 const_cast<cSchedule *
>(Schedule)->SetModified();
900 if (e->StartTime()) {
918 if (e->EndTime() < TimeFrameBegin)
920 if (e->StartTime() > TimeFrameEnd)
924 if (overlap && overlap >= Overlap) {
942 event->DecNumTimers();
1024 isyslog(
"timer %s deferred for %d seconds", *
ToDescr(), Seconds);
1086 Timers->SetExplicitModify();
1091 Timers->SetModified();
1106 if (ti->Id() == Id) {
1107 if (!Remote && !ti->Remote() || Remote && ti->Remote() && strcmp(Remote, ti->Remote()) == 0)
1117 if (!ti->Remote() &&
1118 ti->Channel() == Timer->
Channel() &&
1119 (ti->WeekDays() && ti->WeekDays() == Timer->
WeekDays() || !ti->WeekDays() && ti->Day() == Timer->
Day()) &&
1120 ti->Start() == Timer->
Start() &&
1121 ti->Stop() == Timer->
Stop())
1129 static int LastPending = -1;
1132 if (!ti->Remote() && !ti->Recording() && ti->Matches(t)) {
1133 if (ti->Pending()) {
1134 if (ti->Index() > LastPending) {
1135 LastPending = ti->
Index();
1170 if (ti->Event() == Event && ti->Local() && ti->HasFlags(Flags))
1181 if (!ti->Remote() && ti->Recording())
1182 n =
max(n, ti->Priority());
1191 if (!ti->Remote() && !ti->IsPatternTimer()) {
1193 if ((ti->HasFlags(
tfActive)) && (!t0 || ti->
StopTime() > time(NULL) && ti->Compare(*t0) < 0))
1233 if (Timer->Channel() == Channel)
1241 bool TimersModified =
false;
1243 if (!ti->IsPatternTimer())
1246 return TimersModified;
1251 bool TimersModified =
false;
1253 if (ti->IsPatternTimer() && ti->Local()) {
1255 TimersModified |= ti->SpawnPatternTimers(Schedules,
this);
1258 return TimersModified;
1263 bool TimersModified =
false;
1267 TimersModified |= ti->AdjustSpawnedTimer();
1270 return TimersModified;
1273#define DELETE_EXPIRED_TIMEOUT 30
1279 bool TimersModified =
false;
1288 TimersModified =
true;
1293 return TimersModified;
1298 bool Result =
false;
1299 if (!ServerName || !RemoteTimers || RemoteTimers->
Size() == 0) {
1304 if (Timer->
Remote() && (!ServerName || strcmp(Timer->
Remote(), ServerName) == 0)) {
1315 if (ti->Remote() && strcmp(ti->Remote(), ServerName) == 0)
1323 int sr = RemoteTimers->
Size();
1328 int nl = atoi(tl[il]);
1331 int nr = atoi((*RemoteTimers)[ir]);
1333 AddTimer = DelTimer = nl;
1343 AddTimer = atoi((*RemoteTimers)[ir]);
1345 esyslog(
"ERROR: %s: error in timer settings: %s", ServerName, (*RemoteTimers)[ir]);
1352 if (AddTimer && DelTimer) {
1353 if (strcmp(tl[il], (*RemoteTimers)[ir]) != 0) {
1355 char *v = (*RemoteTimers)[ir];
1356 while (*v && *v !=
' ')
1367 esyslog(
"ERROR: %d@%s: error in timer settings: %s", DelTimer, ServerName, v);
1375 else if (AddTimer) {
1376 char *v = (*RemoteTimers)[ir];
1377 while (*v && *v !=
' ')
1380 if (Timer->
Parse(v)) {
1382 Timer->
SetId(AddTimer);
1387 esyslog(
"ERROR: %s: error in timer settings: %s", ServerName, v);
1392 else if (DelTimer) {
1400 esyslog(
"ERROR: oops while storing remote timers!");
1419 if (OldTimer->
Remote() && OldTimer->
Id()) {
1426 else if (!OldTimer || OldTimer->
Local() || !OldTimer->
Id()) {
1427 if (NewTimer->
Local()) {
1428 if (OldTimer && OldTimer->
Id())
1436 int RemoteId = atoi(
SVDRPValue(Response[0]));
1439 NewTimer->
SetId(RemoteId);
1440 if (OldTimer && OldTimer->
Id()) {
1447 else if (NewTimer->
Local()) {
1454 else if (strcmp(OldTimer->
Remote(), NewTimer->
Remote()) == 0) {
1462 int RemoteId = atoi(
SVDRPValue(Response[0]));
1465 NewTimer->
SetId(RemoteId);
1477 return (*(
const cTimer **)a)->Compare(**(
const cTimer **)b);
1483 for (
const cTimer *Timer = Timers->
First(); Timer; Timer = Timers->
Next(Timer))
#define LOCK_CHANNELS_READ
const char * Name(void) const
tChannelID GetChannelID(void) const
const char * FileName(void)
static int CurrentChannel(void)
Returns the number of the current channel on the primary device.
bool Contains(const char *Title) const
const char * ShortText(void) const
cString ToDescr(void) const
time_t EndTime(void) const
int RunningStatus(void) const
bool IsRunning(bool OrAboutToStart=false) const
void IncNumTimers(void) const
time_t StartTime(void) const
tChannelID ChannelID(void) const
const char * Title(void) const
const cSchedule * Schedule(void) const
bool HasTimer(void) const
void Ins(cListObject *Object, cListObject *Before=NULL)
void Del(cListObject *Object, bool DeleteObject=true)
bool Lock(cStateKey &StateKey, bool Write=false, int TimeoutMs=0) const
Tries to get a lock on this list and returns true if successful.
void Add(cListObject *Object, cListObject *After=NULL)
cListObject * Prev(void) const
cListObject * Next(void) const
const T * First(void) const
Returns the first element in this list, or NULL if the list is empty.
const T * Next(const T *Object) const
< Returns the element immediately before Object in this list, or NULL if Object is the first element ...
bool Modified(int &State) const
bool PresentSeenWithin(int Seconds) const
const cList< cEvent > * Events(void) const
const cSchedule * GetSchedule(tChannelID ChannelID) const
char NameInstantRecord[NAME_MAX+1]
cSortedTimers(const cTimers *Timers)
static void MsgTimerChange(const cTimer *Timer, eTimerChange Change)
void SortNumerically(void)
static cString sprintf(const char *fmt,...) __attribute__((format(printf
void SetAux(const char *Aux)
time_t stopTime
the time_t value calculated from 'day', 'start' and 'stop'
const char * Aux(void) const
void SetLifetime(int Lifetime)
const char * File(void) const
cString PrintFirstDay(void) const
time_t day
midnight of the day this timer shall hit, or of the first day it shall hit in case of a repeating tim...
int weekdays
bitmask, lowest bits: SSFTWTM (the 'M' is the LSB)
bool IsSingleEvent(void) const
void SetPending(bool Pending)
cTimer(bool Instant=false, bool Pause=false, const cChannel *Channel=NULL)
time_t StopTime(void) const
the stop time as given by the user
cString PatternAndFile(void) const
bool Recording(void) const
static time_t SetTime(time_t t, int SecondsFromMidnight)
void ClrFlags(uint Flags)
virtual int Compare(const cListObject &ListObject) const
Must return 0 if this object is equal to ListObject, a positive value if it is "greater",...
void SetFile(const char *File)
void SetFlags(uint Flags)
int start
the start and stop time of this timer as given by the user,
void SetPriority(int Priority)
void SetDeferred(int Seconds)
time_t StopTimeEvent(void) const
or by the user (for normal timers)
bool AdjustSpawnedTimer(void)
void SetInVpsMargin(bool InVpsMargin)
bool IsPatternTimer(void) const
static int GetWDay(time_t t)
const char * Pattern(void) const
static cString PrintDay(time_t Day, int WeekDays, bool SingleByteChars)
void TriggerRespawn(void)
bool DayMatches(time_t t) const
void SetRemote(const char *Remote)
bool InVpsMargin(void) const
bool SetEvent(const cEvent *Event)
void InvFlags(uint Flags)
int stop
in the form hhmm, with hh (00..23) and mm (00..59) added as hh*100+mm
const cEvent * Event(void) const
static bool ParseDay(const char *s, time_t &Day, int &WeekDays)
bool vpsActive
true if this is a VPS timer and the event is current
cTimer * SpawnPatternTimer(const cEvent *Event, cTimers *Timers)
time_t StartTime(void) const
the start time as given by the user
const cChannel * Channel(void) const
void CalcMargins(int &MarginStart, int &MarginStop, const cEvent *Event)
cString ToDescr(void) const
bool SetEventFromSchedule(const cSchedules *Schedules)
void SetRecording(bool Recording)
time_t StartTimeEvent(void) const
the start/stop times as given by the event (for VPS timers), by event plus margins (for spawned non-V...
void SetPattern(const char *Pattern)
char pattern[NAME_MAX *2+1]
static int TimeToInt(int t)
time_t deferred
Matches(time_t, ...) will return false if the current time is before this value.
static int GetMDay(time_t t)
bool HasFlags(uint Flags) const
const char * Remote(void) const
cTimer & operator=(const cTimer &Timer)
time_t vpsNotRunning
the time when a VPS event's running status changed to "not running"
void SetWeekDays(int WeekDays)
bool Matches(time_t t=0, bool Directly=false, int Margin=0) const
bool Parse(const char *s)
cString ToText(bool UseChannelID=false) const
static time_t IncDay(time_t t, int Days)
bool SpawnPatternTimers(const cSchedules *Schedules, cTimers *Timers)
static bool Load(const char *FileName)
int GetMaxPriority(void) const
Returns the maximum priority of all local timers that are currently recording.
const cTimer * UsesChannel(const cChannel *Channel) const
bool StoreRemoteTimers(const char *ServerName=NULL, const cStringList *RemoteTimers=NULL)
Stores the given list of RemoteTimers, which come from the VDR ServerName, in this list.
const cTimer * GetById(int Id, const char *Remote=NULL) const
void Add(cTimer *Timer, cTimer *After=NULL)
static cTimers * GetTimersWrite(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of timers for write access.
void Del(cTimer *Timer, bool DeleteObject=true)
static const cTimers * GetTimersRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of timers for read access.
const cTimer * GetTimer(const cTimer *Timer) const
const cTimer * GetMatch(time_t t) const
const cTimer * GetTimerForEvent(const cEvent *Event, eTimerFlags Flags=tfNone) const
void Ins(cTimer *Timer, cTimer *Before=NULL)
bool SpawnPatternTimers(const cSchedules *Schedules)
const cTimer * GetNextActiveTimer(void) const
bool DeleteExpired(bool Force)
bool SetEvents(const cSchedules *Schedules)
bool AdjustSpawnedTimers(void)
static int NewTimerId(void)
void Sort(__compar_fn_t Compare)
virtual void Append(T Data)
#define TIMERPATTERN_BEGIN
#define TIMERMACRO_BEFORE
#define TIMERMACRO_EPISODE
#define TIMERPATTERN_AVOID
#define LOCK_SCHEDULES_READ
#define LOCK_SCHEDULES_WRITE
@ RunningStatusNotRunning
cDoneRecordings DoneRecordingsPattern
static tChannelID FromString(const char *s)
bool ExecSVDRPCommand(const char *ServerName, const char *Command, cStringList *Response)
Sends the given SVDRP Command string to the remote VDR identified by ServerName and collects all of t...
const char * SVDRPValue(const char *s)
Returns the actual value of the given SVDRP response string, skipping the three digit reply code and ...
int SVDRPCode(const char *s)
Returns the value of the three digit reply code of the given SVDRP response string.
#define DELETE_EXPIRED_TIMEOUT
static bool RemoteTimerError(const cTimer *Timer, cString *Msg)
static cString MakePatternFileName(const char *Pattern, const char *Title, const char *Episode, const char *File)
static bool MatchPattern(const char *Pattern, const char *Title, cString *Before=NULL, cString *Match=NULL, cString *After=NULL)
#define EITPRESENTFOLLOWINGGRACE
#define EITPRESENTFOLLOWINGRATE
static int CompareTimers(const void *a, const void *b)
bool HandleRemoteTimerModifications(cTimer *NewTimer, cTimer *OldTimer, cString *Msg)
Performs any operations necessary to synchronize changes to a timer between peer VDR machines.
#define LOCK_TIMERS_WRITE
bool HandleRemoteTimerModifications(cTimer *NewTimer, cTimer *OldTimer=NULL, cString *Msg=NULL)
Performs any operations necessary to synchronize changes to a timer between peer VDR machines.