45 time_t t = time(NULL);
47 struct tm *now = localtime_r(&t, &tm_r);
50 start = now->tm_hour * 100 + now->tm_min;
54 if (!
Setup.InstantRecordTime &&
channel && (Instant || Pause)) {
57 if (
const cEvent *
Event = Schedule->GetPresentEvent()) {
58 time_t tstart =
Event->StartTime();
59 time_t tstop =
Event->EndTime();
62 tstart =
Event->Vps();
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);
198 if (
Event->Vps() && (PatternTimer ||
Setup.UseVps))
202 channel = Channels->GetByChannelID(
Event->ChannelID(),
true);
204 time_t tstop = tstart +
Event->Duration();
209 tstart -= MarginStart;
213 struct tm *time = localtime_r(&tstart, &tm_r);
216 start = time->tm_hour * 100 + time->tm_min;
217 time = localtime_r(&tstop, &tm_r);
218 stop = time->tm_hour * 100 + time->tm_min;
224 FileName =
Event->Title();
243 event->DecNumTimers();
250 if (&Timer !=
this) {
271 aux = Timer.
aux ? strdup(Timer.
aux) : NULL;
275 event->DecNumTimers();
285 MarginStart =
Setup.MarginStart * 60;
286 MarginStop =
Setup.MarginStop * 60;
291 MarginStart =
max(0,
min(MarginStart, e->Duration() - 60));
293 MarginStop =
max(0,
min(MarginStop, e->Duration() - 60));
327 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 :
"");
340 return (t / 100 * 60 + t % 100) * 60;
357 const char *a = strchr(s,
'@');
358 const char *d = a ? a + 1 : isdigit(*s) ? s : NULL;
360 if (strlen(d) == 10) {
362 if (3 == sscanf(d,
"%d-%d-%d", &tm_r.tm_year, &tm_r.tm_mon, &tm_r.tm_mday)) {
363 tm_r.tm_year -= 1900;
365 tm_r.tm_hour = tm_r.tm_min = tm_r.tm_sec = 0;
375 int day = strtol(d, &tail, 10);
378 time_t t = time(NULL);
379 int DaysToCheck = 61;
380 for (
int i = -1; i <= DaysToCheck; i++) {
389 if (a || !isdigit(*s)) {
390 if ((a && a - s == 7) || strlen(s) == 7) {
391 for (
const char *p = s + 6; p >= s; p--) {
404#define DAYBUFFERSIZE 64
409 const char *w =
trNOOP(
"MTWTFSS");
410 if (!SingleByteChars)
415 for (
int i = 0; i < sl; i++)
429 localtime_r(&
Day, &tm_r);
430 b += strftime(b,
DAYBUFFERSIZE - (b - buffer),
"%Y-%m-%d", &tm_r);
448 char *channelbuffer = NULL;
449 char *daybuffer = NULL;
450 char *filebuffer = NULL;
461 while (l2 > 0 && isspace(s[l2 - 1]))
463 if (s[l2 - 1] ==
':') {
464 s2 =
MALLOC(
char, l2 + 3);
465 strcat(
strn0cpy(s2, s, l2 + 1),
" \n");
469 if (8 <= sscanf(s,
"%u :%m[^:]:%m[^:]:%d :%d :%d :%d :%m[^:\n]:%m[^\n]", &
flags, &channelbuffer, &daybuffer, &
start, &
stop, &
priority, &
lifetime, &filebuffer, &
aux)) {
476 char *fb = filebuffer;
478 if (
char *p = strchr(fb,
'}')) {
491 channel = Channels->GetByNumber(atoi(channelbuffer));
495 esyslog(
"ERROR: channel %s not defined", channelbuffer);
509 return fprintf(f,
"%s\n", *
ToText(
true)) > 0;
521 return localtime_r(&t, &tm_r)->tm_mday;
527 int weekday = localtime_r(&t, &tm_r)->tm_wday;
528 return weekday == 0 ? 6 : weekday - 1;
539 tm tm = *localtime_r(&t, &tm_r);
551 tm tm = *localtime_r(&t, &tm_r);
552 tm.tm_hour = SecondsFromMidnight / 3600;
553 tm.tm_min = (SecondsFromMidnight % 3600) / 60;
554 tm.tm_sec = SecondsFromMidnight % 60;
570#define EITPRESENTFOLLOWINGRATE 10
571#define EITPRESENTFOLLOWINGGRACE 60
581 int length = end - begin;
592 for (
int i = -1; i <= 7; i++) {
599 if ((!
day || a >=
day) && t < b) {
623 if (Margin || !Directly) {
627 const cSchedule *Schedule =
event->Schedule();
634 bool running =
event->IsRunning(
true);
645 return event->IsRunning(
true);
659 if (!Margin && !Directly) {
664 return event->StartTime() -
Setup.MarginStart * 60 <= t && t <
event->EndTime() +
Setup.MarginStop * 60;
673#define FULLMATCH 1000
704 if (
Event->IsRunning())
729#define EXPIRELATENCY 60
734 time_t Now = time(NULL);
738 if (ExpireTime <= Now) {
740 const cSchedule *Schedule =
event ?
event->Schedule() : NULL;
743 FirstEvent = Schedule->
Events()->
Next(FirstEvent);
744 else if ((Schedule = Schedules->GetSchedule(
Channel())) != NULL) {
754 dsyslog(
"timer %s is waiting for next VPS event %s", *
ToDescr(), *e->ToDescr());
761 dsyslog(
"timer %s has no event, setting expiration to +24h", *
ToDescr());
762 ExpireTime += 3600 * 24;
766 return ExpireTime <= Now;
789 return event->StartTime();
791 return event->StartTime() -
Setup.MarginStart * 60;
800 return event->EndTime();
802 return event->EndTime() +
Setup.MarginStop * 60;
807#define EPGLIMITBEFORE (1 * 3600)
808#define EPGLIMITAFTER (1 * 3600)
829 bool TimersSpawned =
false;
833 time_t Now = time(NULL);
839 if (!Timer && e->EndTime() > Now) {
841 TimersSpawned =
true;
851 Limit +=
Setup.MarginStart * 60;
853 if (e->StartTime() <= Limit) {
856 TimersSpawned =
true;
870 return TimersSpawned;
884 tstart -= MarginStart;
893 struct tm *time = localtime_r(&tstart, &tm_r);
895 SetStart(time->tm_hour * 100 + time->tm_min);
896 time = localtime_r(&tstop, &tm_r);
897 SetStop(time->tm_hour * 100 + time->tm_min);
916 const_cast<cSchedule *
>(Schedule)->SetModified();
933 if (e->StartTime()) {
951 if (e->EndTime() < TimeFrameBegin)
953 if (e->StartTime() > TimeFrameEnd)
957 if (overlap && overlap >= Overlap) {
958 if (
Event && overlap == Overlap && e->Duration() <=
Event->Duration())
975 event->DecNumTimers();
978 Event->IncNumTimers();
1057 isyslog(
"timer %s deferred for %d seconds", *
ToDescr(), Seconds);
1119 Timers->SetExplicitModify();
1124 Timers->SetModified();
1139 if (ti->Id() == Id) {
1140 if (!Remote && !ti->Remote() || Remote && ti->Remote() && strcmp(Remote, ti->Remote()) == 0)
1150 if (!ti->Remote() &&
1151 ti->Channel() == Timer->
Channel() &&
1152 (ti->WeekDays() && ti->WeekDays() == Timer->
WeekDays() || !ti->WeekDays() && ti->Day() == Timer->
Day()) &&
1153 ti->Start() == Timer->
Start() &&
1154 ti->Stop() == Timer->
Stop())
1162 static int LastPending = -1;
1166 if (!ti->Remote() && !ti->Recording() && ti->Matches(t)) {
1167 if (ti->Pending()) {
1168 if (ti->Index() > LastPending) {
1169 LastPending = ti->Index();
1204 if (ti->Event() == Event && ti->Local() && ti->HasFlags(Flags))
1215 if (!ti->Remote() && ti->Recording())
1216 n =
max(n, ti->Priority());
1225 if (!ti->Remote() && !ti->IsPatternTimer()) {
1227 if ((ti->HasFlags(
tfActive)) && (!t0 || ti->
StopTime() > time(NULL) && ti->Compare(*t0) < 0))
1236 return timers.Lock(StateKey,
false, TimeoutMs) ? &
timers : NULL;
1241 return timers.Lock(StateKey,
true, TimeoutMs) ? &
timers : NULL;
1267 if (Timer->Channel() == Channel)
1275 bool TimersModified =
false;
1277 if (!ti->IsPatternTimer())
1278 TimersModified |= ti->SetEventFromSchedule(Schedules);
1280 return TimersModified;
1285 bool TimersModified =
false;
1287 if (ti->IsPatternTimer() && ti->Local()) {
1289 TimersModified |= ti->SpawnPatternTimers(Schedules,
this);
1292 return TimersModified;
1297 bool TimersModified =
false;
1301 TimersModified |= ti->AdjustSpawnedTimer();
1304 return TimersModified;
1307#define DELETE_EXPIRED_TIMEOUT 30
1313 bool TimersModified =
false;
1322 TimersModified =
true;
1327 return TimersModified;
1332 bool Result =
false;
1333 if (!ServerName || !RemoteTimers || RemoteTimers->
Size() == 0) {
1338 if (Timer->
Remote() && (!ServerName || strcmp(Timer->
Remote(), ServerName) == 0)) {
1349 if (ti->Remote() && strcmp(ti->Remote(), ServerName) == 0)
1357 int sr = RemoteTimers->
Size();
1362 int nl = atoi(tl[il]);
1365 int nr = atoi((*RemoteTimers)[ir]);
1367 AddTimer = DelTimer = nl;
1377 AddTimer = atoi((*RemoteTimers)[ir]);
1379 esyslog(
"ERROR: %s: error in timer settings: %s", ServerName, (*RemoteTimers)[ir]);
1386 if (AddTimer && DelTimer) {
1387 if (strcmp(tl[il], (*RemoteTimers)[ir]) != 0) {
1389 char *v = (*RemoteTimers)[ir];
1390 while (*v && *v !=
' ')
1401 esyslog(
"ERROR: %d@%s: error in timer settings: %s", DelTimer, ServerName, v);
1409 else if (AddTimer) {
1410 char *v = (*RemoteTimers)[ir];
1411 while (*v && *v !=
' ')
1414 if (Timer->
Parse(v)) {
1416 Timer->
SetId(AddTimer);
1421 esyslog(
"ERROR: %s: error in timer settings: %s", ServerName, v);
1426 else if (DelTimer) {
1434 esyslog(
"ERROR: oops while storing remote timers!");
1453 if (OldTimer->
Remote() && OldTimer->
Id()) {
1460 else if (!OldTimer || OldTimer->
Local() || !OldTimer->
Id()) {
1461 if (NewTimer->
Local()) {
1462 if (OldTimer && OldTimer->
Id())
1470 int RemoteId = atoi(
SVDRPValue(Response[0]));
1473 NewTimer->
SetId(RemoteId);
1474 if (OldTimer && OldTimer->
Id()) {
1481 else if (NewTimer->
Local()) {
1488 else if (strcmp(OldTimer->
Remote(), NewTimer->
Remote()) == 0) {
1496 int RemoteId = atoi(
SVDRPValue(Response[0]));
1499 NewTimer->
SetId(RemoteId);
1511 return (*(
const cTimer **)a)->Compare(**(
const cTimer **)b);
1517 for (
const cTimer *Timer = Timers->
First(); Timer; Timer = Timers->
Next(Timer))
#define LOCK_CHANNELS_READ
cConfig(const char *NeedsLocking=NULL)
const char * FileName(void)
static int CurrentChannel(void)
Returns the number of the current channel on the primary device.
cString ToDescr(void) const
time_t EndTime(void) const
void IncNumTimers(void) const
time_t StartTime(void) const
bool HasTimer(void) const
void Ins(cListObject *Object, cListObject *Before=NULL)
void Del(cListObject *Object, bool DeleteObject=true)
void Add(cListObject *Object, cListObject *After=NULL)
cListObject(const cListObject &ListObject)
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
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)
cVector(const cVector &Vector)
#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.