2002-10-20 12:28:55 +02:00
/*
* timers . c : Timer handling
*
* See the main source file ' vdr . c ' for copyright information and
* how to reach the author .
*
2017-06-25 10:03:19 +02:00
* $ Id : timers . c 4.11 2017 / 06 / 25 10 : 02 : 09 kls Exp $
2002-10-20 12:28:55 +02:00
*/
# include "timers.h"
# include <ctype.h>
2005-09-04 14:48:39 +02:00
# include "device.h"
2002-10-20 12:28:55 +02:00
# include "i18n.h"
2006-03-26 14:38:46 +02:00
# include "libsi/si.h"
2008-02-15 15:46:07 +01:00
# include "recording.h"
2004-07-17 12:48:14 +02:00
# include "remote.h"
2008-02-16 15:04:49 +01:00
# include "status.h"
2015-09-01 11:14:27 +02:00
# include "svdrp.h"
2002-10-20 12:28:55 +02:00
// IMPORTANT NOTE: in the 'sscanf()' calls there is a blank after the '%d'
// format characters in order to allow any number of blanks after a numeric
// value!
2008-02-10 14:11:47 +01:00
// --- cTimer ----------------------------------------------------------------
2002-10-20 12:28:55 +02:00
2015-09-01 11:14:27 +02:00
cTimer : : cTimer ( bool Instant , bool Pause , const cChannel * Channel )
2002-10-20 12:28:55 +02:00
{
2015-09-06 09:14:53 +02:00
id = 0 ;
2002-10-20 12:28:55 +02:00
startTime = stopTime = 0 ;
2015-09-01 11:14:27 +02:00
scheduleState = - 1 ;
2011-08-06 13:20:07 +02:00
deferred = 0 ;
2015-09-01 11:14:27 +02:00
pending = inVpsMargin = false ;
2004-02-29 14:21:22 +01:00
flags = tfNone ;
2012-09-15 13:57:39 +02:00
* file = 0 ;
aux = NULL ;
2015-09-13 13:57:51 +02:00
remote = NULL ;
2012-09-15 13:57:39 +02:00
event = NULL ;
2004-02-29 14:21:22 +01:00
if ( Instant )
SetFlags ( tfActive | tfInstant ) ;
2015-09-01 11:14:27 +02:00
LOCK_CHANNELS_READ ;
channel = Channel ? Channel : Channels - > GetByNumber ( cDevice : : CurrentChannel ( ) ) ;
2002-10-20 12:28:55 +02:00
time_t t = time ( NULL ) ;
struct tm tm_r ;
struct tm * now = localtime_r ( & t , & tm_r ) ;
2005-03-19 15:38:43 +01:00
day = SetTime ( t , 0 ) ;
weekdays = 0 ;
2002-10-20 12:28:55 +02:00
start = now - > tm_hour * 100 + now - > tm_min ;
2012-09-15 13:57:39 +02:00
stop = 0 ;
2013-03-16 10:39:16 +01:00
if ( ! Setup . InstantRecordTime & & channel & & ( Instant | | Pause ) ) {
2015-09-01 11:14:27 +02:00
LOCK_SCHEDULES_READ ;
if ( const cSchedule * Schedule = Schedules - > GetSchedule ( channel ) ) {
if ( const cEvent * Event = Schedule - > GetPresentEvent ( ) ) {
time_t tstart = Event - > StartTime ( ) ;
time_t tstop = Event - > EndTime ( ) ;
if ( Event - > Vps ( ) & & Setup . UseVps ) {
SetFlags ( tfVps ) ;
tstart = Event - > Vps ( ) ;
2012-09-15 13:57:39 +02:00
}
2015-09-01 11:14:27 +02:00
else {
tstop + = Setup . MarginStop * 60 ;
tstart - = Setup . MarginStart * 60 ;
}
day = SetTime ( tstart , 0 ) ;
struct tm * time = localtime_r ( & tstart , & tm_r ) ;
start = time - > tm_hour * 100 + time - > tm_min ;
time = localtime_r ( & tstop , & tm_r ) ;
stop = time - > tm_hour * 100 + time - > tm_min ;
SetEvent ( Event ) ;
2012-09-15 13:57:39 +02:00
}
}
}
if ( ! stop ) {
stop = now - > tm_hour * 60 + now - > tm_min + ( Setup . InstantRecordTime ? Setup . InstantRecordTime : DEFINSTRECTIME ) ;
stop = ( stop / 60 ) * 100 + ( stop % 60 ) ;
}
2002-10-20 12:28:55 +02:00
if ( stop > = 2400 )
stop - = 2400 ;
2003-05-11 14:10:00 +02:00
priority = Pause ? Setup . PausePriority : Setup . DefaultPriority ;
lifetime = Pause ? Setup . PauseLifetime : Setup . DefaultLifetime ;
2002-10-20 12:28:55 +02:00
if ( Instant & & channel )
snprintf ( file , sizeof ( file ) , " %s%s " , Setup . MarkInstantRecord ? " @ " : " " , * Setup . NameInstantRecord ? Setup . NameInstantRecord : channel - > Name ( ) ) ;
}
2003-12-22 13:29:24 +01:00
cTimer : : cTimer ( const cEvent * Event )
2002-10-20 12:28:55 +02:00
{
2015-09-06 09:14:53 +02:00
id = 0 ;
2002-10-20 12:28:55 +02:00
startTime = stopTime = 0 ;
2015-09-01 11:14:27 +02:00
scheduleState = - 1 ;
2011-08-06 13:20:07 +02:00
deferred = 0 ;
2015-09-01 11:14:27 +02:00
pending = inVpsMargin = false ;
2004-02-29 14:21:22 +01:00
flags = tfActive ;
2012-09-15 13:57:39 +02:00
* file = 0 ;
aux = NULL ;
2015-09-13 13:57:51 +02:00
remote = NULL ;
2012-09-15 13:57:39 +02:00
event = NULL ;
2004-02-29 14:21:22 +01:00
if ( Event - > Vps ( ) & & Setup . UseVps )
SetFlags ( tfVps ) ;
2015-09-01 11:14:27 +02:00
LOCK_CHANNELS_READ ;
channel = Channels - > GetByChannelID ( Event - > ChannelID ( ) , true ) ;
2004-02-29 14:21:22 +01:00
time_t tstart = ( flags & tfVps ) ? Event - > Vps ( ) : Event - > StartTime ( ) ;
time_t tstop = tstart + Event - > Duration ( ) ;
if ( ! ( HasFlags ( tfVps ) ) ) {
tstop + = Setup . MarginStop * 60 ;
tstart - = Setup . MarginStart * 60 ;
}
2002-10-20 12:28:55 +02:00
struct tm tm_r ;
struct tm * time = localtime_r ( & tstart , & tm_r ) ;
2005-03-19 15:38:43 +01:00
day = SetTime ( tstart , 0 ) ;
weekdays = 0 ;
2002-10-20 12:28:55 +02:00
start = time - > tm_hour * 100 + time - > tm_min ;
time = localtime_r ( & tstop , & tm_r ) ;
stop = time - > tm_hour * 100 + time - > tm_min ;
if ( stop > = 2400 )
stop - = 2400 ;
priority = Setup . DefaultPriority ;
lifetime = Setup . DefaultLifetime ;
2003-12-22 13:29:24 +01:00
const char * Title = Event - > Title ( ) ;
2002-10-20 12:28:55 +02:00
if ( ! isempty ( Title ) )
2007-06-16 10:41:21 +02:00
Utf8Strn0Cpy ( file , Event - > Title ( ) , sizeof ( file ) ) ;
2012-09-15 13:57:39 +02:00
SetEvent ( Event ) ;
2002-10-20 12:28:55 +02:00
}
2006-09-08 15:06:09 +02:00
cTimer : : cTimer ( const cTimer & Timer )
{
channel = NULL ;
aux = NULL ;
2015-09-01 11:14:27 +02:00
remote = NULL ;
2006-09-08 15:06:09 +02:00
event = NULL ;
2008-04-13 12:45:15 +02:00
flags = tfNone ;
2006-09-08 15:06:09 +02:00
* this = Timer ;
}
2002-10-20 12:28:55 +02:00
cTimer : : ~ cTimer ( )
{
2015-09-01 11:14:27 +02:00
if ( event )
event - > DecNumTimers ( ) ;
2006-02-25 12:09:22 +01:00
free ( aux ) ;
2015-09-01 11:14:27 +02:00
free ( remote ) ;
2002-10-20 12:28:55 +02:00
}
cTimer & cTimer : : operator = ( const cTimer & Timer )
{
2006-09-08 15:06:09 +02:00
if ( & Timer ! = this ) {
2015-09-06 09:14:53 +02:00
id = Timer . id ;
2006-09-08 15:06:09 +02:00
startTime = Timer . startTime ;
stopTime = Timer . stopTime ;
2015-09-01 11:14:27 +02:00
scheduleState = - 1 ;
deferred = 0 ;
2006-09-08 15:06:09 +02:00
pending = Timer . pending ;
inVpsMargin = Timer . inVpsMargin ;
2015-09-13 13:57:51 +02:00
flags = Timer . flags ;
2006-09-08 15:06:09 +02:00
channel = Timer . channel ;
day = Timer . day ;
weekdays = Timer . weekdays ;
start = Timer . start ;
stop = Timer . stop ;
priority = Timer . priority ;
lifetime = Timer . lifetime ;
strncpy ( file , Timer . file , sizeof ( file ) ) ;
free ( aux ) ;
aux = Timer . aux ? strdup ( Timer . aux ) : NULL ;
2015-09-01 11:14:27 +02:00
free ( remote ) ;
remote = Timer . remote ? strdup ( Timer . remote ) : NULL ;
if ( event )
event - > DecNumTimers ( ) ;
event = Timer . event ;
if ( event )
event - > IncNumTimers ( ) ;
2006-09-08 15:06:09 +02:00
}
2002-10-20 12:28:55 +02:00
return * this ;
}
2004-11-01 10:40:38 +01:00
int cTimer : : Compare ( const cListObject & ListObject ) const
2002-10-20 12:28:55 +02:00
{
2012-06-02 12:10:36 +02:00
const cTimer * ti = ( const cTimer * ) & ListObject ;
2002-10-20 12:28:55 +02:00
time_t t1 = StartTime ( ) ;
time_t t2 = ti - > StartTime ( ) ;
2004-11-01 10:40:38 +01:00
int r = t1 - t2 ;
if ( r = = 0 )
r = ti - > priority - priority ;
return r ;
2002-10-20 12:28:55 +02:00
}
2008-02-16 15:04:49 +01:00
cString cTimer : : ToText ( bool UseChannelID ) const
2002-10-20 12:28:55 +02:00
{
2002-11-10 15:50:21 +01:00
strreplace ( file , ' : ' , ' | ' ) ;
2015-09-10 10:39:45 +02:00
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 , file , aux ? aux : " " ) ;
2002-11-10 15:50:21 +01:00
strreplace ( file , ' | ' , ' : ' ) ;
2008-02-15 14:57:48 +01:00
return buffer ;
2002-10-20 12:28:55 +02:00
}
2005-03-20 15:15:42 +01:00
cString cTimer : : ToDescr ( void ) const
{
2015-09-06 09:14:53 +02:00
return cString : : sprintf ( " %d%s%s (%d %04d-%04d %s'%s') " , Id ( ) , remote ? " @ " : " " , remote ? remote : " " , Channel ( ) - > Number ( ) , start , stop , HasFlags ( tfVps ) ? " VPS " : " " , file ) ;
2005-03-20 15:15:42 +01:00
}
2002-10-20 12:28:55 +02:00
int cTimer : : TimeToInt ( int t )
{
return ( t / 100 * 60 + t % 100 ) * 60 ;
}
2005-03-19 15:38:43 +01:00
bool cTimer : : ParseDay ( const char * s , time_t & Day , int & WeekDays )
{
// possible formats are:
// 19
// 2005-03-19
// MTWTFSS
// MTWTFSS@19
// MTWTFSS@2005-03-19
Day = 0 ;
WeekDays = 0 ;
s = skipspace ( s ) ;
if ( ! * s )
return false ;
const char * a = strchr ( s , ' @ ' ) ;
const char * d = a ? a + 1 : isdigit ( * s ) ? s : NULL ;
if ( d ) {
if ( strlen ( d ) = = 10 ) {
struct tm tm_r ;
if ( 3 = = sscanf ( d , " %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
Day = mktime ( & tm_r ) ;
2002-10-20 12:28:55 +02:00
}
2005-03-19 15:38:43 +01:00
else
return false ;
}
else {
// handle "day of month" for compatibility with older versions:
char * tail = NULL ;
2005-06-11 14:30:26 +02:00
int day = strtol ( d , & tail , 10 ) ;
2005-03-19 15:38:43 +01:00
if ( tail & & * tail | | day < 1 | | day > 31 )
return false ;
time_t t = time ( NULL ) ;
int DaysToCheck = 61 ; // 61 to handle months with 31/30/31
for ( int i = - 1 ; i < = DaysToCheck ; i + + ) {
time_t t0 = IncDay ( t , i ) ;
if ( GetMDay ( t0 ) = = day ) {
Day = SetTime ( t0 , 0 ) ;
break ;
}
}
2002-10-20 12:28:55 +02:00
}
}
2005-03-19 15:38:43 +01:00
if ( a | | ! isdigit ( * s ) ) {
if ( ( a & & a - s = = 7 ) | | strlen ( s ) = = 7 ) {
for ( const char * p = s + 6 ; p > = s ; p - - ) {
WeekDays < < = 1 ;
WeekDays | = ( * p ! = ' - ' ) ;
}
}
else
return false ;
}
return true ;
2002-10-20 12:28:55 +02:00
}
2007-06-10 13:02:43 +02:00
cString cTimer : : PrintDay ( time_t Day , int WeekDays , bool SingleByteChars )
2002-10-20 12:28:55 +02:00
{
2007-06-10 13:02:43 +02:00
# define DAYBUFFERSIZE 64
2004-12-26 12:45:22 +01:00
char buffer [ DAYBUFFERSIZE ] ;
2005-03-19 15:38:43 +01:00
char * b = buffer ;
if ( WeekDays ) {
2007-08-11 12:39:06 +02:00
// TRANSLATORS: the first character of each weekday, beginning with monday
const char * w = trNOOP ( " MTWTFSS " ) ;
2007-06-10 13:02:43 +02:00
if ( ! SingleByteChars )
w = tr ( w ) ;
2002-10-20 12:28:55 +02:00
while ( * w ) {
2007-06-10 13:02:43 +02:00
int sl = Utf8CharLen ( w ) ;
if ( WeekDays & 1 ) {
for ( int i = 0 ; i < sl ; i + + )
b [ i ] = w [ i ] ;
b + = sl ;
}
else
* b + + = ' - ' ;
2005-03-19 15:38:43 +01:00
WeekDays > > = 1 ;
2007-06-10 13:02:43 +02:00
w + = sl ;
2002-10-20 12:28:55 +02:00
}
2005-03-19 15:38:43 +01:00
if ( Day )
* b + + = ' @ ' ;
}
if ( Day ) {
struct tm tm_r ;
localtime_r ( & Day , & tm_r ) ;
b + = strftime ( b , DAYBUFFERSIZE - ( b - buffer ) , " %Y-%m-%d " , & tm_r ) ;
2002-10-20 12:28:55 +02:00
}
2005-03-19 15:38:43 +01:00
* b = 0 ;
2002-10-20 12:28:55 +02:00
return buffer ;
}
2005-03-20 15:15:42 +01:00
cString cTimer : : PrintFirstDay ( void ) const
2002-10-20 12:28:55 +02:00
{
2005-03-19 15:38:43 +01:00
if ( weekdays ) {
2007-06-10 13:02:43 +02:00
cString s = PrintDay ( day , weekdays , true ) ;
2002-10-20 12:28:55 +02:00
if ( strlen ( s ) = = 18 )
2004-12-26 12:45:22 +01:00
return * s + 8 ;
2002-10-20 12:28:55 +02:00
}
return " " ; // not NULL, so the caller can always use the result
}
bool cTimer : : Parse ( const char * s )
{
2002-11-10 15:50:21 +01:00
char * channelbuffer = NULL ;
char * daybuffer = NULL ;
char * filebuffer = NULL ;
2006-02-25 12:09:22 +01:00
free ( aux ) ;
aux = NULL ;
2013-12-28 11:37:42 +01:00
//XXX Apparently sscanf() doesn't work correctly if the last %m argument
2012-06-09 14:40:26 +02:00
//XXX results in an empty string (this first occurred when the EIT gathering
2002-10-20 12:28:55 +02:00
//XXX was put into a separate thread - don't know why this happens...
//XXX As a cure we copy the original string and add a blank.
//XXX If anybody can shed some light on why sscanf() failes here, I'd love
//XXX to hear about that!
char * s2 = NULL ;
int l2 = strlen ( s ) ;
while ( l2 > 0 & & isspace ( s [ l2 - 1 ] ) )
l2 - - ;
if ( s [ l2 - 1 ] = = ' : ' ) {
s2 = MALLOC ( char , l2 + 3 ) ;
strcat ( strn0cpy ( s2 , s , l2 + 1 ) , " \n " ) ;
s = s2 ;
}
2002-11-10 15:50:21 +01:00
bool result = false ;
2013-12-28 11:37:42 +01:00
if ( 8 < = sscanf ( s , " %u :%m[^:]:%m[^:]:%d :%d :%d :%d :%m[^: \n ]:%m[^ \n ] " , & flags , & channelbuffer , & daybuffer , & start , & stop , & priority , & lifetime , & filebuffer , & aux ) ) {
2006-02-25 12:09:22 +01:00
if ( aux & & ! * skipspace ( aux ) ) {
free ( aux ) ;
aux = NULL ;
2002-10-20 12:28:55 +02:00
}
//TODO add more plausibility checks
2005-03-19 15:38:43 +01:00
result = ParseDay ( daybuffer , day , weekdays ) ;
2009-08-09 12:45:36 +02:00
Utf8Strn0Cpy ( file , filebuffer , sizeof ( file ) ) ;
2002-10-20 12:28:55 +02:00
strreplace ( file , ' | ' , ' : ' ) ;
2015-09-01 11:14:27 +02:00
LOCK_CHANNELS_READ ;
2004-01-04 12:30:00 +01:00
if ( isnumber ( channelbuffer ) )
2015-09-01 11:14:27 +02:00
channel = Channels - > GetByNumber ( atoi ( channelbuffer ) ) ;
2004-01-04 12:30:00 +01:00
else
2015-09-01 11:14:27 +02:00
channel = Channels - > GetByChannelID ( tChannelID : : FromString ( channelbuffer ) , true , true ) ;
2002-10-20 12:28:55 +02:00
if ( ! channel ) {
2002-11-10 15:50:21 +01:00
esyslog ( " ERROR: channel %s not defined " , channelbuffer ) ;
result = false ;
2002-10-20 12:28:55 +02:00
}
}
2002-11-10 15:50:21 +01:00
free ( channelbuffer ) ;
free ( daybuffer ) ;
free ( filebuffer ) ;
2002-10-20 12:28:55 +02:00
free ( s2 ) ;
2002-11-10 15:50:21 +01:00
return result ;
2002-10-20 12:28:55 +02:00
}
bool cTimer : : Save ( FILE * f )
{
2015-09-01 11:14:27 +02:00
if ( ! Remote ( ) )
2015-09-10 10:39:45 +02:00
return fprintf ( f , " %s \n " , * ToText ( true ) ) > 0 ;
2015-09-01 11:14:27 +02:00
return true ;
2002-10-20 12:28:55 +02:00
}
2004-11-01 10:40:38 +01:00
bool cTimer : : IsSingleEvent ( void ) const
2002-10-20 12:28:55 +02:00
{
2005-03-19 15:38:43 +01:00
return ! weekdays ;
2002-10-20 12:28:55 +02:00
}
2004-11-14 16:27:27 +01:00
int cTimer : : GetMDay ( time_t t )
2002-10-20 12:28:55 +02:00
{
struct tm tm_r ;
return localtime_r ( & t , & tm_r ) - > tm_mday ;
}
2004-11-14 16:27:27 +01:00
int cTimer : : GetWDay ( time_t t )
2002-10-20 12:28:55 +02:00
{
struct tm tm_r ;
int weekday = localtime_r ( & t , & tm_r ) - > tm_wday ;
2006-04-21 15:15:18 +02:00
return weekday = = 0 ? 6 : weekday - 1 ; // we start with Monday==0!
2002-10-20 12:28:55 +02:00
}
2004-11-01 10:40:38 +01:00
bool cTimer : : DayMatches ( time_t t ) const
2002-10-20 12:28:55 +02:00
{
2005-03-19 15:38:43 +01:00
return IsSingleEvent ( ) ? SetTime ( t , 0 ) = = day : ( weekdays & ( 1 < < GetWDay ( t ) ) ) ! = 0 ;
2002-10-20 12:28:55 +02:00
}
time_t cTimer : : 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
}
time_t cTimer : : 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 ) ;
}
2012-02-20 15:53:33 +01:00
void cTimer : : SetFile ( const char * File )
2002-10-20 12:28:55 +02:00
{
if ( ! isempty ( File ) )
2007-06-16 10:41:21 +02:00
Utf8Strn0Cpy ( file , File , sizeof ( file ) ) ;
2002-10-20 12:28:55 +02:00
}
2012-02-27 10:21:28 +01:00
# define EITPRESENTFOLLOWINGRATE 10 // max. seconds between two occurrences of the "EIT present/following table for the actual multiplex" (2s by the standard, using some more for safety)
2006-04-09 09:12:47 +02:00
bool cTimer : : Matches ( time_t t , bool Directly , int Margin ) const
2002-10-20 12:28:55 +02:00
{
startTime = stopTime = 0 ;
if ( t = = 0 )
t = time ( NULL ) ;
int begin = TimeToInt ( start ) ; // seconds from midnight
int length = TimeToInt ( stop ) - begin ;
if ( length < 0 )
length + = SECSINDAY ;
2005-03-19 15:38:43 +01:00
if ( IsSingleEvent ( ) ) {
startTime = SetTime ( day , begin ) ;
stopTime = startTime + length ;
}
else {
for ( int i = - 1 ; i < = 7 ; i + + ) {
2006-05-25 12:44:07 +02:00
time_t t0 = IncDay ( day ? max ( day , t ) : t , i ) ;
2005-03-19 15:38:43 +01:00
if ( DayMatches ( t0 ) ) {
time_t a = SetTime ( t0 , begin ) ;
time_t b = a + length ;
2006-08-05 12:06:11 +02:00
if ( ( ! day | | a > = day ) & & t < b ) {
2005-03-19 15:38:43 +01:00
startTime = a ;
stopTime = b ;
break ;
}
2002-10-20 12:28:55 +02:00
}
}
2005-03-19 15:38:43 +01:00
if ( ! startTime )
2006-05-25 12:44:07 +02:00
startTime = IncDay ( t , 7 ) ; // just to have something that's more than a week in the future
2005-03-19 15:38:43 +01:00
else if ( ! Directly & & ( t > startTime | | t > day + SECSINDAY + 3600 ) ) // +3600 in case of DST change
day = 0 ;
}
2004-02-29 14:21:22 +01:00
2011-08-06 13:20:07 +02:00
if ( t < deferred )
return false ;
deferred = 0 ;
2004-02-29 14:21:22 +01:00
if ( HasFlags ( tfActive ) ) {
2006-05-07 09:01:59 +02:00
if ( HasFlags ( tfVps ) & & event & & event - > Vps ( ) ) {
if ( Margin | | ! Directly ) {
startTime = event - > StartTime ( ) ;
stopTime = event - > EndTime ( ) ;
2012-02-27 10:21:28 +01:00
if ( ! Margin ) { // this is an actual check
2015-09-01 11:14:27 +02:00
if ( event - > Schedule ( ) - > PresentSeenWithin ( EITPRESENTFOLLOWINGRATE ) ) // VPS control can only work with up-to-date events...
return event - > IsRunning ( true ) ;
2012-10-16 08:24:10 +02:00
return startTime < = t & & t < stopTime ; // ...otherwise we fall back to normal timer handling
2012-02-27 10:21:28 +01:00
}
2006-05-07 09:01:59 +02:00
}
2004-02-29 14:21:22 +01:00
}
2006-04-09 09:12:47 +02:00
return startTime < = t + Margin & & t < stopTime ; // must stop *before* stopTime to allow adjacent timers
2004-02-29 14:21:22 +01:00
}
return false ;
}
2005-03-13 11:42:59 +01:00
# define FULLMATCH 1000
2012-12-08 11:05:39 +01:00
eTimerMatch cTimer : : Matches ( const cEvent * Event , int * Overlap ) const
2004-02-29 14:21:22 +01:00
{
2005-03-20 13:13:02 +01:00
// Overlap is the percentage of the Event's duration that is covered by
// this timer (based on FULLMATCH for finer granularity than just 100).
// To make sure a VPS timer can be distinguished from a plain 100% overlap,
// it gets an additional 100 added, and a VPS event that is actually running
// gets 200 added to the FULLMATCH.
2017-06-25 10:03:19 +02:00
if ( channel - > GetChannelID ( ) = = Event - > ChannelID ( ) ) {
2004-02-29 14:21:22 +01:00
bool UseVps = HasFlags ( tfVps ) & & Event - > Vps ( ) ;
2005-03-13 11:42:59 +01:00
Matches ( UseVps ? Event - > Vps ( ) : Event - > StartTime ( ) , true ) ;
2005-06-18 13:32:03 +02:00
int overlap = 0 ;
2005-03-13 11:42:59 +01:00
if ( UseVps )
overlap = ( startTime = = Event - > Vps ( ) ) ? FULLMATCH + ( Event - > IsRunning ( ) ? 200 : 100 ) : 0 ;
2005-06-18 13:32:03 +02:00
if ( ! overlap ) {
if ( startTime < = Event - > StartTime ( ) & & Event - > EndTime ( ) < = stopTime )
overlap = FULLMATCH ;
else if ( stopTime < = Event - > StartTime ( ) | | Event - > EndTime ( ) < = startTime )
overlap = 0 ;
else
overlap = ( min ( stopTime , Event - > EndTime ( ) ) - max ( startTime , Event - > StartTime ( ) ) ) * FULLMATCH / max ( Event - > Duration ( ) , 1 ) ;
}
2004-02-29 14:21:22 +01:00
startTime = stopTime = 0 ;
2005-03-13 11:42:59 +01:00
if ( Overlap )
* Overlap = overlap ;
2006-04-01 13:27:14 +02:00
if ( UseVps )
return overlap > FULLMATCH ? tmFull : tmNone ;
return overlap > = FULLMATCH ? tmFull : overlap > 0 ? tmPartial : tmNone ;
2004-02-29 14:21:22 +01:00
}
return tmNone ;
2002-10-20 12:28:55 +02:00
}
2005-03-20 11:19:36 +01:00
# define EXPIRELATENCY 60 // seconds (just in case there's a short glitch in the VPS signal)
2005-03-20 15:15:42 +01:00
bool cTimer : : Expired ( void ) const
2005-03-20 11:19:36 +01:00
{
2009-06-21 14:08:51 +02:00
return IsSingleEvent ( ) & & ! Recording ( ) & & StopTime ( ) + EXPIRELATENCY < = time ( NULL ) & & ( ! HasFlags ( tfVps ) | | ! event | | ! event - > Vps ( ) ) ;
2005-03-20 11:19:36 +01:00
}
2004-11-01 10:40:38 +01:00
time_t cTimer : : StartTime ( void ) const
2002-10-20 12:28:55 +02:00
{
if ( ! startTime )
Matches ( ) ;
return startTime ;
}
2004-11-01 10:40:38 +01:00
time_t cTimer : : StopTime ( void ) const
2002-10-20 12:28:55 +02:00
{
if ( ! stopTime )
Matches ( ) ;
return stopTime ;
}
2006-02-28 12:44:00 +01:00
# define EPGLIMITBEFORE (1 * 3600) // Time in seconds before a timer's start time and
# define EPGLIMITAFTER (1 * 3600) // after its stop time within which EPG events will be taken into consideration.
2006-02-25 15:57:56 +01:00
2015-09-06 09:14:53 +02:00
void cTimer : : SetId ( int Id )
{
id = Id ;
}
2015-09-01 11:14:27 +02:00
bool cTimer : : SetEventFromSchedule ( const cSchedules * Schedules )
2006-02-25 15:57:56 +01:00
{
const cSchedule * Schedule = Schedules - > GetSchedule ( Channel ( ) ) ;
2006-04-01 13:27:14 +02:00
if ( Schedule & & Schedule - > Events ( ) - > First ( ) ) {
2015-09-01 11:14:27 +02:00
if ( Schedule - > Modified ( scheduleState ) ) {
2006-02-25 15:57:56 +01:00
const cEvent * Event = NULL ;
2006-04-01 13:27:14 +02:00
if ( HasFlags ( tfVps ) & & Schedule - > Events ( ) - > First ( ) - > Vps ( ) ) {
// VPS timers only match if their start time exactly matches the event's VPS time:
for ( const cEvent * e = Schedule - > Events ( ) - > First ( ) ; e ; e = Schedule - > Events ( ) - > Next ( e ) ) {
2006-04-09 09:12:47 +02:00
if ( e - > StartTime ( ) & & e - > RunningStatus ( ) ! = SI : : RunningStatusNotRunning ) { // skip outdated events
int overlap = 0 ;
Matches ( e , & overlap ) ;
if ( overlap > FULLMATCH ) {
Event = e ;
break ; // take the first matching event
}
2006-04-01 13:27:14 +02:00
}
}
}
else {
// Normal timers match the event they have the most overlap with:
int Overlap = 0 ;
// Set up the time frame within which to check events:
Matches ( 0 , true ) ;
time_t TimeFrameBegin = StartTime ( ) - EPGLIMITBEFORE ;
time_t TimeFrameEnd = StopTime ( ) + EPGLIMITAFTER ;
for ( const cEvent * e = Schedule - > Events ( ) - > First ( ) ; e ; e = Schedule - > Events ( ) - > Next ( e ) ) {
2006-03-25 11:39:57 +01:00
if ( e - > EndTime ( ) < TimeFrameBegin )
continue ; // skip events way before the timer starts
if ( e - > StartTime ( ) > TimeFrameEnd )
break ; // the rest is way after the timer ends
2006-04-01 13:27:14 +02:00
int overlap = 0 ;
Matches ( e , & overlap ) ;
if ( overlap & & overlap > = Overlap ) {
if ( Event & & overlap = = Overlap & & e - > Duration ( ) < = Event - > Duration ( ) )
2006-02-25 15:57:56 +01:00
continue ; // if overlap is the same, we take the longer event
2006-04-01 13:27:14 +02:00
Overlap = overlap ;
Event = e ;
2006-02-25 15:57:56 +01:00
}
}
2006-04-01 13:27:14 +02:00
}
2015-09-01 11:14:27 +02:00
return SetEvent ( Event ) ;
2006-02-25 15:57:56 +01:00
}
}
2015-09-01 11:14:27 +02:00
return false ;
2006-02-25 15:57:56 +01:00
}
2015-09-01 11:14:27 +02:00
bool cTimer : : SetEvent ( const cEvent * Event )
2004-02-29 14:21:22 +01:00
{
2015-09-01 11:14:27 +02:00
if ( event ! = Event ) {
if ( event )
event - > DecNumTimers ( ) ;
if ( Event ) {
2006-03-25 12:51:29 +01:00
isyslog ( " timer %s set to event %s " , * ToDescr ( ) , * Event - > ToDescr ( ) ) ;
2015-09-01 11:14:27 +02:00
Event - > IncNumTimers ( ) ;
Event - > Schedule ( ) - > Modified ( scheduleState ) ; // to get the current state
}
else {
2005-03-20 15:15:42 +01:00
isyslog ( " timer %s set to no event " , * ToDescr ( ) ) ;
2015-09-01 11:14:27 +02:00
scheduleState = - 1 ;
}
2004-02-29 14:21:22 +01:00
event = Event ;
2015-09-01 11:14:27 +02:00
return true ;
2004-02-29 14:21:22 +01:00
}
2015-09-01 11:14:27 +02:00
return false ;
2004-02-29 14:21:22 +01:00
}
2002-10-20 12:28:55 +02:00
void cTimer : : SetRecording ( bool Recording )
{
2015-09-01 11:14:27 +02:00
if ( Recording )
2005-05-07 11:10:56 +02:00
SetFlags ( tfRecording ) ;
else
ClrFlags ( tfRecording ) ;
2015-09-01 11:14:27 +02:00
isyslog ( " timer %s %s " , * ToDescr ( ) , Recording ? " start " : " stop " ) ;
2002-10-20 12:28:55 +02:00
}
void cTimer : : SetPending ( bool Pending )
{
pending = Pending ;
}
2004-02-29 14:21:22 +01:00
void cTimer : : SetInVpsMargin ( bool InVpsMargin )
{
if ( InVpsMargin & & ! inVpsMargin )
2005-03-20 15:15:42 +01:00
isyslog ( " timer %s entered VPS margin " , * ToDescr ( ) ) ;
2004-02-29 14:21:22 +01:00
inVpsMargin = InVpsMargin ;
}
2012-02-20 15:37:01 +01:00
void cTimer : : SetDay ( time_t Day )
{
day = Day ;
}
void cTimer : : SetWeekDays ( int WeekDays )
{
weekdays = WeekDays ;
}
void cTimer : : SetStart ( int Start )
{
start = Start ;
}
void cTimer : : SetStop ( int Stop )
{
stop = Stop ;
}
2006-01-03 11:46:57 +01:00
void cTimer : : SetPriority ( int Priority )
{
2006-01-08 11:44:37 +01:00
priority = Priority ;
2006-01-03 11:46:57 +01:00
}
2012-02-20 15:37:01 +01:00
void cTimer : : SetLifetime ( int Lifetime )
{
lifetime = Lifetime ;
}
void cTimer : : SetAux ( const char * Aux )
{
free ( aux ) ;
2015-09-01 11:14:27 +02:00
aux = Aux ? strdup ( Aux ) : NULL ;
}
void cTimer : : SetRemote ( const char * Remote )
{
free ( remote ) ;
remote = Remote ? strdup ( Remote ) : NULL ;
2012-02-20 15:37:01 +01:00
}
2011-08-06 13:20:07 +02:00
void cTimer : : SetDeferred ( int Seconds )
{
deferred = time ( NULL ) + Seconds ;
isyslog ( " timer %s deferred for %d seconds " , * ToDescr ( ) , Seconds ) ;
}
2006-01-06 14:31:57 +01:00
void cTimer : : SetFlags ( uint Flags )
2004-02-29 14:21:22 +01:00
{
flags | = Flags ;
}
2006-01-06 14:31:57 +01:00
void cTimer : : ClrFlags ( uint Flags )
2002-10-20 12:28:55 +02:00
{
2004-02-29 14:21:22 +01:00
flags & = ~ Flags ;
}
2006-01-06 14:31:57 +01:00
void cTimer : : InvFlags ( uint Flags )
2004-02-29 14:21:22 +01:00
{
flags ^ = Flags ;
}
2006-01-06 14:31:57 +01:00
bool cTimer : : HasFlags ( uint Flags ) const
2004-02-29 14:21:22 +01:00
{
return ( flags & Flags ) = = Flags ;
2002-10-20 12:28:55 +02:00
}
void cTimer : : Skip ( void )
{
2005-03-19 15:38:43 +01:00
day = IncDay ( SetTime ( StartTime ( ) , 0 ) , 1 ) ;
2006-05-25 14:38:04 +02:00
startTime = 0 ;
2006-02-25 15:57:56 +01:00
SetEvent ( NULL ) ;
2002-10-20 12:28:55 +02:00
}
void cTimer : : OnOff ( void )
{
if ( IsSingleEvent ( ) )
2004-02-29 14:21:22 +01:00
InvFlags ( tfActive ) ;
2005-03-19 15:38:43 +01:00
else if ( day ) {
day = 0 ;
2004-02-29 14:21:22 +01:00
ClrFlags ( tfActive ) ;
2002-10-20 12:28:55 +02:00
}
2004-02-29 14:21:22 +01:00
else if ( HasFlags ( tfActive ) )
2002-10-20 12:28:55 +02:00
Skip ( ) ;
else
2004-02-29 14:21:22 +01:00
SetFlags ( tfActive ) ;
2006-02-25 15:57:56 +01:00
SetEvent ( NULL ) ;
2002-10-20 12:28:55 +02:00
Matches ( ) ; // refresh start and end time
}
2008-02-10 14:11:47 +01:00
// --- cTimers ---------------------------------------------------------------
2002-10-20 12:28:55 +02:00
2015-09-01 11:14:27 +02:00
cTimers cTimers : : timers ;
2015-09-06 09:14:53 +02:00
int cTimers : : lastTimerId = 0 ;
2002-10-20 12:28:55 +02:00
2004-10-24 15:01:50 +02:00
cTimers : : cTimers ( void )
2017-05-28 12:47:54 +02:00
: cConfig < cTimer > ( " 1 Timers " )
2004-10-24 15:01:50 +02:00
{
2006-03-26 14:38:46 +02:00
lastDeleteExpired = 0 ;
2004-10-24 15:01:50 +02:00
}
2015-09-01 11:14:27 +02:00
bool cTimers : : Load ( const char * FileName )
{
LOCK_TIMERS_WRITE ;
Timers - > SetExplicitModify ( ) ;
if ( timers . cConfig < cTimer > : : Load ( FileName ) ) {
for ( cTimer * ti = timers . First ( ) ; ti ; ti = timers . Next ( ti ) ) {
2015-09-10 10:39:45 +02:00
ti - > SetId ( NewTimerId ( ) ) ;
2015-09-01 11:14:27 +02:00
ti - > ClrFlags ( tfRecording ) ;
Timers - > SetModified ( ) ;
}
return true ;
}
return false ;
}
2015-09-10 10:39:45 +02:00
int cTimers : : NewTimerId ( void )
{
return + + lastTimerId ; // no need for locking, the caller must have a lock on the global Timers list
}
2017-04-20 10:08:04 +02:00
const cTimer * cTimers : : GetById ( int Id , const char * Remote ) const
2015-09-06 09:14:53 +02:00
{
for ( const cTimer * ti = First ( ) ; ti ; ti = Next ( ti ) ) {
2017-04-20 10:08:04 +02:00
if ( ti - > Id ( ) = = Id ) {
if ( ! Remote & & ! ti - > Remote ( ) | | Remote & & ti - > Remote ( ) & & strcmp ( Remote , ti - > Remote ( ) ) = = 0 )
return ti ;
}
2015-09-06 09:14:53 +02:00
}
return NULL ;
}
2016-12-22 14:27:01 +01:00
const cTimer * cTimers : : GetTimer ( const cTimer * Timer ) const
2002-10-20 12:28:55 +02:00
{
2016-12-22 14:27:01 +01:00
for ( const cTimer * ti = First ( ) ; ti ; ti = Next ( ti ) ) {
2015-09-01 11:14:27 +02:00
if ( ! ti - > Remote ( ) & &
ti - > Channel ( ) = = Timer - > Channel ( ) & &
2005-09-09 15:28:26 +02:00
( ti - > WeekDays ( ) & & ti - > WeekDays ( ) = = Timer - > WeekDays ( ) | | ! ti - > WeekDays ( ) & & ti - > Day ( ) = = Timer - > Day ( ) ) & &
ti - > Start ( ) = = Timer - > Start ( ) & &
ti - > Stop ( ) = = Timer - > Stop ( ) )
2002-10-20 12:28:55 +02:00
return ti ;
}
return NULL ;
}
2015-09-01 11:14:27 +02:00
const cTimer * cTimers : : GetMatch ( time_t t ) const
2002-10-20 12:28:55 +02:00
{
2006-02-03 15:25:51 +01:00
static int LastPending = - 1 ;
2015-09-01 11:14:27 +02:00
const cTimer * t0 = NULL ;
for ( const cTimer * ti = First ( ) ; ti ; ti = Next ( ti ) ) {
if ( ! ti - > Remote ( ) & & ! ti - > Recording ( ) & & ti - > Matches ( t ) ) {
2006-02-03 15:25:51 +01:00
if ( ti - > Pending ( ) ) {
2013-03-29 15:37:16 +01:00
if ( ti - > Index ( ) > LastPending ) {
2006-02-03 15:25:51 +01:00
LastPending = ti - > Index ( ) ;
2013-03-29 15:37:16 +01:00
return ti ;
}
2006-02-03 15:25:51 +01:00
else
continue ;
}
2002-10-20 12:28:55 +02:00
if ( ! t0 | | ti - > Priority ( ) > t0 - > Priority ( ) )
t0 = ti ;
}
}
2006-02-03 15:25:51 +01:00
if ( ! t0 )
LastPending = - 1 ;
2002-10-20 12:28:55 +02:00
return t0 ;
}
2015-09-01 11:14:27 +02:00
const cTimer * cTimers : : GetMatch ( const cEvent * Event , eTimerMatch * Match ) const
2004-02-29 14:21:22 +01:00
{
2015-09-01 11:14:27 +02:00
const cTimer * t = NULL ;
2012-12-08 11:05:39 +01:00
eTimerMatch m = tmNone ;
2015-09-01 11:14:27 +02:00
for ( const cTimer * ti = First ( ) ; ti ; ti = Next ( ti ) ) {
2012-12-08 11:05:39 +01:00
eTimerMatch tm = ti - > Matches ( Event ) ;
2004-02-29 14:21:22 +01:00
if ( tm > m ) {
t = ti ;
m = tm ;
if ( m = = tmFull )
break ;
}
}
if ( Match )
* Match = m ;
return t ;
}
2015-09-01 11:14:27 +02:00
const cTimer * cTimers : : GetNextActiveTimer ( void ) const
2002-10-20 12:28:55 +02:00
{
2015-09-01 11:14:27 +02:00
const cTimer * t0 = NULL ;
for ( const cTimer * ti = First ( ) ; ti ; ti = Next ( ti ) ) {
if ( ! ti - > Remote ( ) ) {
ti - > Matches ( ) ;
if ( ( ti - > HasFlags ( tfActive ) ) & & ( ! t0 | | ti - > StopTime ( ) > time ( NULL ) & & ti - > Compare ( * t0 ) < 0 ) )
t0 = ti ;
}
2002-10-20 12:28:55 +02:00
}
return t0 ;
}
2004-02-29 14:21:22 +01:00
2015-09-01 11:14:27 +02:00
const cTimers * cTimers : : GetTimersRead ( cStateKey & StateKey , int TimeoutMs )
2004-10-31 10:22:32 +01:00
{
2015-09-01 11:14:27 +02:00
return timers . Lock ( StateKey , false , TimeoutMs ) ? & timers : NULL ;
}
cTimers * cTimers : : GetTimersWrite ( cStateKey & StateKey , int TimeoutMs )
{
return timers . Lock ( StateKey , true , TimeoutMs ) ? & timers : NULL ;
2004-10-31 10:22:32 +01:00
}
2008-02-16 15:04:49 +01:00
void cTimers : : Add ( cTimer * Timer , cTimer * After )
{
2015-09-06 09:14:53 +02:00
if ( ! Timer - > Remote ( ) )
2015-09-10 10:39:45 +02:00
Timer - > SetId ( NewTimerId ( ) ) ;
2008-02-16 15:04:49 +01:00
cConfig < cTimer > : : Add ( Timer , After ) ;
cStatus : : MsgTimerChange ( Timer , tcAdd ) ;
}
void cTimers : : Ins ( cTimer * Timer , cTimer * Before )
{
cConfig < cTimer > : : Ins ( Timer , Before ) ;
cStatus : : MsgTimerChange ( Timer , tcAdd ) ;
}
void cTimers : : Del ( cTimer * Timer , bool DeleteObject )
{
cStatus : : MsgTimerChange ( Timer , tcDel ) ;
cConfig < cTimer > : : Del ( Timer , DeleteObject ) ;
}
2015-09-01 11:14:27 +02:00
const cTimer * cTimers : : UsesChannel ( const cChannel * Channel ) const
2004-10-31 10:22:32 +01:00
{
2015-09-01 11:14:27 +02:00
for ( const cTimer * Timer = First ( ) ; Timer ; Timer = Next ( Timer ) ) {
if ( Timer - > Channel ( ) = = Channel )
return Timer ;
}
return NULL ;
2004-10-31 10:22:32 +01:00
}
2015-09-01 11:14:27 +02:00
bool cTimers : : SetEvents ( const cSchedules * Schedules )
2004-02-29 14:21:22 +01:00
{
2015-09-01 11:14:27 +02:00
bool TimersModified = false ;
for ( cTimer * ti = First ( ) ; ti ; ti = Next ( ti ) )
TimersModified | = ti - > SetEventFromSchedule ( Schedules ) ;
return TimersModified ;
2004-02-29 14:21:22 +01:00
}
2005-03-20 11:19:36 +01:00
2015-09-01 11:14:27 +02:00
bool cTimers : : DeleteExpired ( void )
2005-03-20 11:19:36 +01:00
{
2006-03-26 14:38:46 +02:00
if ( time ( NULL ) - lastDeleteExpired < 30 )
2015-09-01 11:14:27 +02:00
return false ;
bool TimersModified = false ;
2005-03-20 11:19:36 +01:00
cTimer * ti = First ( ) ;
while ( ti ) {
cTimer * next = Next ( ti ) ;
2015-09-01 11:14:27 +02:00
if ( ! ti - > Remote ( ) & & ti - > Expired ( ) ) {
2005-03-20 15:15:42 +01:00
isyslog ( " deleting timer %s " , * ti - > ToDescr ( ) ) ;
2005-03-20 11:19:36 +01:00
Del ( ti ) ;
2015-09-01 11:14:27 +02:00
TimersModified = true ;
2005-03-20 11:19:36 +01:00
}
ti = next ;
}
2006-03-26 14:38:46 +02:00
lastDeleteExpired = time ( NULL ) ;
2015-09-01 11:14:27 +02:00
return TimersModified ;
}
bool cTimers : : GetRemoteTimers ( const char * ServerName )
{
bool Result = false ;
if ( ServerName ) {
Result = DelRemoteTimers ( ServerName ) ;
2015-09-10 10:39:45 +02:00
cStringList Response ;
if ( ExecSVDRPCommand ( ServerName , " LSTT ID " , & Response ) ) {
for ( int i = 0 ; i < Response . Size ( ) ; i + + ) {
const char * s = Response [ i ] ;
int Code = SVDRPCode ( s ) ;
2015-09-01 11:14:27 +02:00
if ( Code = = 250 ) {
2015-09-10 10:39:45 +02:00
if ( const char * v = SVDRPValue ( s ) ) {
2015-09-06 09:14:53 +02:00
int Id = atoi ( v ) ;
2015-09-01 11:14:27 +02:00
while ( * v & & * v ! = ' ' )
2015-09-06 09:14:53 +02:00
v + + ; // skip id
2015-09-01 11:14:27 +02:00
cTimer * Timer = new cTimer ;
if ( Timer - > Parse ( v ) ) {
Timer - > SetRemote ( ServerName ) ;
2015-09-06 09:14:53 +02:00
Timer - > SetId ( Id ) ;
2015-09-01 11:14:27 +02:00
Add ( Timer ) ;
Result = true ;
}
else {
esyslog ( " ERROR: %s: error in timer settings: %s " , ServerName , v ) ;
delete Timer ;
}
}
}
else if ( Code ! = 550 )
esyslog ( " ERROR: %s: %s " , ServerName , s ) ;
}
return Result ;
}
}
else {
cStringList ServerNames ;
if ( GetSVDRPServerNames ( & ServerNames , sffTimers ) ) {
for ( int i = 0 ; i < ServerNames . Size ( ) ; i + + )
Result | = GetRemoteTimers ( ServerNames [ i ] ) ;
}
}
return Result ;
}
bool cTimers : : DelRemoteTimers ( const char * ServerName )
{
bool Deleted = false ;
cTimer * Timer = First ( ) ;
while ( Timer ) {
cTimer * t = Next ( Timer ) ;
if ( Timer - > Remote ( ) & & ( ! ServerName | | strcmp ( Timer - > Remote ( ) , ServerName ) = = 0 ) ) {
Del ( Timer ) ;
Deleted = true ;
}
Timer = t ;
}
return Deleted ;
}
void cTimers : : TriggerRemoteTimerPoll ( const char * ServerName )
{
if ( ServerName ) {
2015-09-10 10:39:45 +02:00
if ( ! ExecSVDRPCommand ( ServerName , cString : : sprintf ( " POLL %s TIMERS " , Setup . SVDRPHostName ) ) )
2015-09-08 11:08:06 +02:00
esyslog ( " ERROR: can't send 'POLL %s TIMERS' to '%s' " , Setup . SVDRPHostName , ServerName ) ;
2015-09-01 11:14:27 +02:00
}
else {
cStringList ServerNames ;
if ( GetSVDRPServerNames ( & ServerNames ) ) {
for ( int i = 0 ; i < ServerNames . Size ( ) ; i + + )
TriggerRemoteTimerPoll ( ServerNames [ i ] ) ;
}
}
2005-03-20 11:19:36 +01:00
}
2012-06-02 12:10:36 +02:00
2017-03-30 15:25:20 +02:00
static bool RemoteTimerError ( const cTimer * Timer , cString * Msg )
{
if ( Msg )
* Msg = cString : : sprintf ( " %s %d@%s! " , tr ( " Error while accessing remote timer " ) , Timer - > Id ( ) , Timer - > Remote ( ) ) ;
return false ; // convenience return code
}
bool HandleRemoteTimerModifications ( cTimer * NewTimer , cTimer * OldTimer , cString * Msg )
{
cStringList Response ;
if ( ! NewTimer ) {
if ( OldTimer ) { // timer shall be deleted from remote machine
if ( OldTimer - > Remote ( ) & & OldTimer - > Id ( ) ) {
if ( ! ExecSVDRPCommand ( OldTimer - > Remote ( ) , cString : : sprintf ( " DELT %d " , OldTimer - > Id ( ) ) , & Response ) | | SVDRPCode ( Response [ 0 ] ) ! = 250 )
return RemoteTimerError ( OldTimer , Msg ) ;
}
isyslog ( " deleted timer %s " , * OldTimer - > ToDescr ( ) ) ;
}
}
else if ( ! OldTimer | | OldTimer - > Local ( ) | | ! OldTimer - > Id ( ) ) {
if ( NewTimer - > Local ( ) ) { // timer stays local, nothing to do
if ( OldTimer & & OldTimer - > Id ( ) )
isyslog ( " modified timer %s " , * NewTimer - > ToDescr ( ) ) ;
else
isyslog ( " added timer %s " , * NewTimer - > ToDescr ( ) ) ;
}
else { // timer is new, or moved from local to remote
if ( ! ExecSVDRPCommand ( NewTimer - > Remote ( ) , cString : : sprintf ( " NEWT %s " , * NewTimer - > ToText ( true ) ) , & Response ) | | SVDRPCode ( Response [ 0 ] ) ! = 250 )
return RemoteTimerError ( NewTimer , Msg ) ;
int RemoteId = atoi ( SVDRPValue ( Response [ 0 ] ) ) ;
if ( RemoteId < = 0 )
return RemoteTimerError ( NewTimer , Msg ) ;
NewTimer - > SetId ( RemoteId ) ;
if ( OldTimer & & OldTimer - > Id ( ) ) {
isyslog ( " moved timer %d to %s " , OldTimer - > Id ( ) , * NewTimer - > ToDescr ( ) ) ;
}
else
isyslog ( " added timer %s " , * NewTimer - > ToDescr ( ) ) ;
}
}
else if ( NewTimer - > Local ( ) ) { // timer is moved from remote to local
if ( ! ExecSVDRPCommand ( OldTimer - > Remote ( ) , cString : : sprintf ( " DELT %d " , OldTimer - > Id ( ) ) , & Response ) | | SVDRPCode ( Response [ 0 ] ) ! = 250 )
return RemoteTimerError ( OldTimer , Msg ) ;
NewTimer - > SetId ( cTimers : : NewTimerId ( ) ) ;
NewTimer - > ClrFlags ( tfRecording ) ; // in case it was recording on the remote machine
isyslog ( " moved timer %d@%s to %s " , OldTimer - > Id ( ) , OldTimer - > Remote ( ) , * NewTimer - > ToDescr ( ) ) ;
}
else if ( strcmp ( OldTimer - > Remote ( ) , NewTimer - > Remote ( ) ) = = 0 ) { // timer stays remote on same machine
if ( ! ExecSVDRPCommand ( OldTimer - > Remote ( ) , cString : : sprintf ( " MODT %d %s " , OldTimer - > Id ( ) , * NewTimer - > ToText ( true ) ) , & Response ) | | SVDRPCode ( Response [ 0 ] ) ! = 250 )
return RemoteTimerError ( NewTimer , Msg ) ;
isyslog ( " modified timer %s " , * NewTimer - > ToDescr ( ) ) ;
}
else { // timer is moved from one remote machine to an other
if ( ! ExecSVDRPCommand ( NewTimer - > Remote ( ) , cString : : sprintf ( " NEWT %s " , * NewTimer - > ToText ( true ) ) , & Response ) | | SVDRPCode ( Response [ 0 ] ) ! = 250 )
return RemoteTimerError ( NewTimer , Msg ) ;
int RemoteId = atoi ( SVDRPValue ( Response [ 0 ] ) ) ;
if ( RemoteId < = 0 )
return RemoteTimerError ( NewTimer , Msg ) ;
NewTimer - > SetId ( RemoteId ) ;
if ( ! ExecSVDRPCommand ( OldTimer - > Remote ( ) , cString : : sprintf ( " DELT %d " , OldTimer - > Id ( ) ) , & Response ) | | SVDRPCode ( Response [ 0 ] ) ! = 250 )
return RemoteTimerError ( OldTimer , Msg ) ;
isyslog ( " moved timer %d@%s to %s " , OldTimer - > Id ( ) , OldTimer - > Remote ( ) , * NewTimer - > ToDescr ( ) ) ;
}
return true ;
}
2012-06-02 12:10:36 +02:00
// --- cSortedTimers ---------------------------------------------------------
static int CompareTimers ( const void * a , const void * b )
{
return ( * ( const cTimer * * ) a ) - > Compare ( * * ( const cTimer * * ) b ) ;
}
2015-09-01 11:14:27 +02:00
cSortedTimers : : cSortedTimers ( const cTimers * Timers )
: cVector < const cTimer * > ( Timers - > Count ( ) )
2012-06-02 12:10:36 +02:00
{
2015-09-01 11:14:27 +02:00
for ( const cTimer * Timer = Timers - > First ( ) ; Timer ; Timer = Timers - > Next ( Timer ) )
2012-06-02 12:10:36 +02:00
Append ( Timer ) ;
Sort ( CompareTimers ) ;
}