Add support for limited activitym periods for a rule

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/ec/trunk@38358 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2015-02-23 10:55:02 +00:00
parent db6fc5df31
commit 31498b9afe
2 changed files with 319 additions and 4 deletions

View file

@ -119,6 +119,42 @@
* of enhanced posix regular expressions. If this is not present,
* any message text will match.
* </desc>
* <term>ActiveFrom</term>
* <desc>A date/time specifying the earliest point at which this rule
* may match any alarm. If the current date/time is earlier than
* this (optional) value then the rule simply can't match.
* </desc>
* <term>ActiveTo</term>
* <desc>A date/time specifying the latest point at which this rule
* may match any alarm. If the current date/time is later than
* this (optional) value then the rule simply can't match.
* </desc>
* <term>ActiveTimes</term>
* <desc>Either a string containing a comma separated list of ranges
* of times specified using a 24 hour clock, or a dictionary of such
* strings keyed on the days of the week (Monday, Tuesday, Wednesday,
* Thursday, Friday, Saturday, Sunday), possibly with an asterisk used
* as the key for a default string to be used for any day not listed. <br />
* If a simple string, the list applies to all days of the week
* (equivalent to a dictionary containing a single string keyed on
* an asterisk).<br />
* The times are in HH:MM format or may simply be the hours (HH) with
* a minute value of zero implied.<br />
* The range separator is a dash/minus, and the range includes the
* first value and excludes the second one.<br />
* eg. 10:45-11 means that the rule is active in the 15 minute interval
* from 10:45 until 11:00 but becomes inactive again at 11:00<br />
* The end of each range must be later than the start of the range,
* and the starts of each successive range must be later than or equal
* to the end of the preceding range.<br />
* As a special case the time 24:00 may be used as the end of the
* last range in a list.<br />
* If this field is simply omitted, the rule is active all day every day.
* </desc>
* <term>ActiveTimezone</term>
* <desc>The formal name of the time zone in which the system checks
* active date/time information. If omitted, the GMT timezone is assumed.
* </desc>
* <term>Stop</term>
* <desc>A boolean (YES or NO) saying whether rule matching should
* stop if this rule is matched. If this is NO (the default) then

View file

@ -253,12 +253,13 @@ replaceFields(NSDictionary *fields, NSString *template)
- (BOOL) setRules: (NSArray*)ra
{
NSUInteger i = 0;
NSMutableArray *r = AUTORELEASE([ra mutableCopy]);
NSUInteger i;
for (i = 0; i < [r count]; i++)
{
NSMutableDictionary *md;
NSObject *obj;
NSString *str;
Regex *val;
@ -344,6 +345,204 @@ replaceFields(NSDictionary *fields, NSString *template)
RELEASE(val);
}
str = [md objectForKey: @"ActiveFrom"];
if (nil != str)
{
NSDate *d = [NSDate dateWithString: str];
if (nil == d)
{
NSLog(@"ActiveFrom='%@' is not a valid date/time", str);
return NO;
}
else
{
[md setObject: d forKey: @"ActiveFrom"];
}
}
str = [md objectForKey: @"ActiveTo"];
if (nil != str)
{
NSDate *d = [NSDate dateWithString: str];
if (nil == d)
{
NSLog(@"ActiveTo='%@' is not a valid date/time", str);
return NO;
}
else
{
[md setObject: d forKey: @"ActiveTo"];
}
}
str = [md objectForKey: @"ActiveTimezone"];
if (nil != str)
{
NSTimeZone *d = [NSTimeZone timeZoneWithName: str];
if (nil == d)
{
NSLog(@"ActiveTimezone='%@' is not a valid time zone", str);
return NO;
}
[md setObject: d forKey: @"ActiveTimeZone"];
}
obj = [md objectForKey: @"ActiveTimes"];
if ([obj isKindOfClass: [NSString class]])
{
obj = (NSString*)[NSDictionary dictionaryWithObjectsAndKeys:
obj, @"*", nil];
}
if ([obj isKindOfClass: [NSDictionary class]])
{
NSMutableDictionary *t = [[obj mutableCopy] autorelease];
NSEnumerator *e = [[t allKeys] objectEnumerator];
while (nil != (str = [e nextObject]))
{
NSString *k = [str stringByTrimmingSpaces];
NSMutableArray *a;
NSUInteger j;
NSInteger lastMinute = 0;
if (YES == [k isEqual: @"*"])
{
k = @"*";
}
else if (YES == [k caseInsensitiveCompare: @"Monday"])
{
k = @"Monday";
}
else if (YES == [k caseInsensitiveCompare: @"Tuesday"])
{
k = @"Tuesday";
}
else if (YES == [k caseInsensitiveCompare: @"Wednesday"])
{
k = @"Wednesday";
}
else if (YES == [k caseInsensitiveCompare: @"Thursday"])
{
k = @"Thursday";
}
else if (YES == [k caseInsensitiveCompare: @"Friday"])
{
k = @"Friday";
}
else if (YES == [k caseInsensitiveCompare: @"Saturday"])
{
k = @"Saturday";
}
else if (YES == [k caseInsensitiveCompare: @"Sunday"])
{
k = @"Sunday";
}
else
{
NSLog(@"ActiveTimes='%@' with bad day of week", obj);
return NO;
}
a = [[[[t objectForKey: str] componentsSeparatedByString: @","]
mutableCopy] autorelease];
j = [a count];
while (j-- > 0)
{
NSMutableArray *r;
int from;
int to;
int h;
int m;
int c;
str = [[a objectAtIndex: j] stringByTrimmingSpaces];
if ([str length] == 0)
{
[a removeObjectAtIndex: j];
continue;
}
r = [[[str componentsSeparatedByString: @"-"]
mutableCopy] autorelease];
if ([r count] != 2)
{
NSLog(@"ActiveTimes='%@' with missing '-' in time range",
obj);
return NO;
}
str = [r objectAtIndex: 0];
c = sscanf([str UTF8String], "%d:%d", &h, &m);
if (0 == c)
{
NSLog(@"ActiveTimes='%@' with missing HH:MM", obj);
return NO;
}
if (1 != c) m = 0;
if (h < 0 || h > 23)
{
NSLog(@"ActiveTimes='%@' with hour out of range", obj);
}
if (m < 0 || m > 59)
{
NSLog(@"ActiveTimes='%@' with minute out of range", obj);
return NO;
}
from = (h * 60) + m;
str = [r objectAtIndex: 1];
c = sscanf([str UTF8String], "%d:%d", &h, &m);
if (0 == c)
{
NSLog(@"ActiveTimes='%@' with missing HH:MM", obj);
return NO;
}
if (1 != c) m = 0;
if (h < 0 || h > 24 || (24 == h && 0 != m))
{
NSLog(@"ActiveTimes='%@' with hour out of range", obj);
}
if (m < 0 || m > 59)
{
NSLog(@"ActiveTimes='%@' with minute out of range", obj);
return NO;
}
if (0 == h && 0 == m)
{
h = 24;
}
to = (h * 60) + m;
if (to <= from)
{
NSLog(@"ActiveTimes='%@' range end earlier than start",
obj);
return NO;
}
if (from < lastMinute)
{
NSLog(@"ActiveTimes='%@' range start earlier than"
@" preceding one", obj);
return NO;
}
lastMinute = to;
[r replaceObjectAtIndex: 0
withObject: [NSNumber numberWithInt: from]];
[r replaceObjectAtIndex: 1
withObject: [NSNumber numberWithInt: to]];
[a replaceObjectAtIndex: j withObject: r];
}
if (0 == [a count])
{
NSLog(@"ActiveTimes='%@' with empty time range", obj);
return NO;
}
[t setObject: a forKey: k];
}
[md setObject: obj forKey: @"ActiveTimes"];
}
else if (obj != nil)
{
NSLog(@"ActiveTimes='%@' is not valid", obj);
return NO;
}
}
ASSIGN(rules, r);
return YES;
@ -440,12 +639,17 @@ replaceFields(NSDictionary *fields, NSString *template)
- (void) applyRules: (NSArray*)rulesArray
toEvent: (EcAlerterEvent*)event
{
CREATE_AUTORELEASE_POOL(pool);
BOOL found = NO;
NSUInteger i;
NSAutoreleasePool *pool = nil;
NSTimeZone *tz = nil;
BOOL found = NO;
NSCalendarDate *now = [NSCalendarDate date];
NSUInteger minuteOfDay = 0;
NSUInteger dayOfWeek = 0;
NSUInteger i;
for (i = 0; i < [rulesArray count]; i++)
{
NSDictionary *times;
NSDictionary *d;
NSString *match = nil;
Regex *e;
@ -456,6 +660,80 @@ replaceFields(NSDictionary *fields, NSString *template)
pool = [NSAutoreleasePool new];
d = [rulesArray objectAtIndex: i];
times = [d objectForKey: @"ActiveTimes"];
if (nil != times)
{
NSDate *from = [d objectForKey: @"ActiveFrom"];
NSDate *to = [d objectForKey: @"ActiveTo"];
BOOL match = NO;
if ((nil == from || [from earlierDate: now] == from)
&& (nil == to || [to laterDate: now] == to))
{
NSTimeZone *z = [d objectForKey: @"ActiveTimezone"];
NSArray *ranges;
NSUInteger index;
if (nil == z)
{
static NSTimeZone *gmt = nil;
if (nil == gmt)
{
gmt = [[NSTimeZone timeZoneWithName: @"GMT"] retain];
}
z = gmt;
}
if (NO == [z isEqual: tz])
{
ASSIGN(tz, z);
[now setTimeZone: tz];
minuteOfDay = [now hourOfDay] * 60 + [now minuteOfHour];
dayOfWeek = [now dayOfWeek];
}
switch (dayOfWeek)
{
case 0: ranges = [times objectForKey: @"Sunday"]; break;
case 1: ranges = [times objectForKey: @"Monday"]; break;
case 2: ranges = [times objectForKey: @"Tuesday"]; break;
case 3: ranges = [times objectForKey: @"Wednesday"]; break;
case 4: ranges = [times objectForKey: @"Thursday"]; break;
case 5: ranges = [times objectForKey: @"Friday"]; break;
default: ranges = [times objectForKey: @"Saturday"]; break;
}
if (nil == ranges)
{
ranges = [times objectForKey: @"*"];
}
index = [ranges count];
while (index-- > 0)
{
NSArray *range;
NSUInteger start;
range = [ranges objectAtIndex: index];
start = [[range objectAtIndex: 0] unsignedIntegerValue];
if (minuteOfDay >= start)
{
NSUInteger end;
end = [[range objectAtIndex: 1] unsignedIntegerValue];
if (minuteOfDay < end)
{
match = YES;
}
break;
}
}
}
if (NO == match)
{
continue;
}
}
s = [d objectForKey: @"Tagged"];
if (s != nil && NO == [s isEqual: [event->m objectForKey: @"Tag"]])
{
@ -816,6 +1094,7 @@ replaceFields(NSDictionary *fields, NSString *template)
NSLog(@"No match of %@ with %@", event->m, rulesArray);
}
}
DESTROY(tz);
RELEASE(pool);
}