diff --git a/ChangeLog b/ChangeLog index 6975717..167e615 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2013-03-18: Niels Grewe + * EcAlerter.h + * EcAlerter.m: + Rearrange and expose a few methods so that subclasses can + easily inject alert rules. + * EcControl.m: + Allow dynamically loading the alerter class based on the + AlerterBundle key in AlertConfig.plist + 2013-03-18 Richard Frith-Macdonald * EcProcess.h: diff --git a/EcAlerter.h b/EcAlerter.h index 8413bf7..68c199a 100644 --- a/EcAlerter.h +++ b/EcAlerter.h @@ -49,6 +49,7 @@ GSMimeSMTPClient *smtp; } - (BOOL) configure: (NSNotification*)n; +- (BOOL) configureWithDefaults: (NSDictionary*)c; - (void) handleInfo: (NSString*)str; - (void) flushEmail; - (void) flushSms; @@ -56,5 +57,6 @@ - (void) mail: (NSMutableDictionary*)m to: (NSArray*)destinations; - (void) sms: (NSMutableDictionary*)m to: (NSArray*)destinations; - (void) timeout: (NSTimer*)t; +- (BOOL) setRules: (NSArray*)ra; @end diff --git a/EcAlerter.m b/EcAlerter.m index 57ae9b2..b61fafd 100644 --- a/EcAlerter.m +++ b/EcAlerter.m @@ -252,21 +252,28 @@ replaceFields(NSDictionary *fields) { NSUserDefaults *d; NSDictionary *c; - NSMutableArray *r; - unsigned int i; d = [EcProc cmdDefaults]; c = [d dictionaryForKey: @"Alerter"]; + return [self configureWithDefaults: c]; +} +- (BOOL) configureWithDefaults: (NSDictionary*)c +{ ASSIGNCOPY(eHost, [c objectForKey: @"EmailHost"]); ASSIGNCOPY(eFrom, [c objectForKey: @"EmailFrom"]); ASSIGNCOPY(ePort, [c objectForKey: @"EmailPort"]); + return [self setRules: [c objectForKey: @"Rules"]]; +} - /* - * Cache a copy of the Rules with modifications to store information - * so we don't need to regenerate it every time we check a message. - */ - r = [[[c objectForKey: @"Rules"] mutableCopy] autorelease]; +/* + * Cache a copy of the Rules with modifications to store information + * so we don't need to regenerate it every time we check a message. + */ +- (BOOL)setRules: (NSArray*)ra +{ + NSUInteger i = 0; + NSMutableArray *r = AUTORELEASE([ra mutableCopy]); for (i = 0; i < [r count]; i++) { NSMutableDictionary *md; diff --git a/EcControl.m b/EcControl.m index 2302d98..3d22b35 100644 --- a/EcControl.m +++ b/EcControl.m @@ -2345,6 +2345,40 @@ static NSString* cmdWord(NSArray* a, unsigned int pos) from: nil]; } + +- (Class)_loadClassFromBundle: (NSString*)bundleName +{ + NSString *path = nil; + Class c = Nil; + NSBundle *bundle = nil; + path = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, + NSLocalDomainMask, YES) lastObject]; + path = [path stringByAppendingPathComponent: @"Bundles"]; + path = [path stringByAppendingPathComponent: bundleName]; + path = [path stringByAppendingPathExtension: @"bundle"]; + bundle = [NSBundle bundleWithPath: path]; + + if (nil == bundle) + { + [[self cmdLogFile: logname] printf: + @"Couldn't load bundle '%@'", bundleName]; + } + else if (Nil == (c = [bundle principalClass])) + { + [[self cmdLogFile: logname] printf: + @"Couldn't load principal class from %@" + @" at %@.", bundleName, path]; + } + else if (NO == [c isSubclassOfClass: [EcAlerter class]]) + { + [[self cmdLogFile: logname] printf: + @"%@ is not a subclass of EcAlerter", + NSStringFromClass(c)]; + c = Nil; + } + return c; +} + - (BOOL) update { NSMutableDictionary *dict; @@ -2358,6 +2392,7 @@ static NSString* cmdWord(NSArray* a, unsigned int pos) unsigned count; unsigned i; BOOL changed = NO; + Class alerterClass = Nil; host = [NSHost currentHost]; str = [NSHost controlWellKnownName]; @@ -2393,10 +2428,40 @@ static NSString* cmdWord(NSArray* a, unsigned int pos) d, @"Alerter", nil]; [[self cmdDefaults] setConfiguration: d]; changed = YES; + } + NSString *alerterDef = [[d objectForKey: @"Alerter"] + objectForKey: @"AlerterBundle"]; + if (nil == alerterDef) + { + alerterClass = [EcAlerter class]; + } + else + { + // First, let's try whether this corresponds to + // a class we already loaded. + alerterClass = NSClassFromString(alerterDef); + if (Nil == alerterClass) + { + // We didn't link the class. Try to load it + // from a bundle. + alerterClass = + [self _loadClassFromBundle: alerterDef]; + } + + } + if (Nil == alerterClass) + { + NSLog(@"Could not load alerter class '%@'", alerterDef); + } + else if ([alerter class] != alerterClass) + { + DESTROY(alerter); + } + if (nil == alerter) { - alerter = [EcAlerter new]; + alerter = [alerterClass new]; } }