2012-02-19 11:59:22 +00:00
|
|
|
|
2012-02-19 12:53:41 +00:00
|
|
|
/** Enterprise Control Configuration and Logging
|
|
|
|
|
|
|
|
Copyright (C) 2012 Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
Written by: Richard Frith-Macdonald <rfm@gnu.org>
|
|
|
|
Date: Febrary 2010
|
|
|
|
Originally developed from 1996 to 2012 by Brainstorm, and donated to
|
|
|
|
the FSF.
|
|
|
|
|
|
|
|
This file is part of the GNUstep project.
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 3 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
License along with this library; if not, write to the Free
|
|
|
|
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02111 USA.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2012-02-19 11:59:22 +00:00
|
|
|
#import <Foundation/Foundation.h>
|
|
|
|
#import <GNUstepBase/GSMime.h>
|
|
|
|
|
2012-05-08 16:08:30 +00:00
|
|
|
#import "EcHost.h"
|
2012-02-19 11:59:22 +00:00
|
|
|
#import "EcProcess.h"
|
2013-04-07 10:56:03 +00:00
|
|
|
#import "EcAlarm.h"
|
2012-02-19 11:59:22 +00:00
|
|
|
#import "EcAlerter.h"
|
|
|
|
#import "NSFileHandle+Printf.h"
|
|
|
|
|
|
|
|
#include <regex.h>
|
|
|
|
|
|
|
|
@interface Regex: NSObject
|
|
|
|
{
|
|
|
|
regex_t regex;
|
|
|
|
BOOL built;
|
|
|
|
}
|
|
|
|
- (id) initWithString: (NSString*)pattern;
|
|
|
|
- (NSString*) match: (NSString*)string;
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation Regex
|
|
|
|
- (void) dealloc
|
|
|
|
{
|
|
|
|
if (built == YES)
|
|
|
|
{
|
|
|
|
built = NO;
|
|
|
|
regfree(®ex);
|
|
|
|
}
|
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id) initWithString: (NSString*)pattern
|
|
|
|
{
|
|
|
|
if (regcomp(®ex, [pattern UTF8String], REG_EXTENDED) != 0)
|
|
|
|
{
|
|
|
|
NSLog(@"Failed to compile regex - '%@'", pattern);
|
|
|
|
DESTROY(self);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
built = YES;
|
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString*) match: (NSString*)string
|
|
|
|
{
|
|
|
|
regmatch_t matches[2];
|
|
|
|
const char *str = [string UTF8String];
|
|
|
|
|
2013-04-07 10:56:03 +00:00
|
|
|
if (0 == str)
|
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
2012-02-19 11:59:22 +00:00
|
|
|
if (regexec(®ex, str, 1, matches, 0) != 0)
|
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int l = matches[0].rm_eo - matches[0].rm_so;
|
|
|
|
char b[l+1];
|
|
|
|
|
|
|
|
memcpy(b, &str[matches[0].rm_so], l);
|
|
|
|
b[l] = '\0';
|
|
|
|
return [NSString stringWithUTF8String: b];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@end
|
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
@interface EcAlerterEvent : NSObject
|
|
|
|
{
|
|
|
|
@public
|
|
|
|
NSMutableDictionary *m;
|
|
|
|
NSString *hostName;
|
|
|
|
NSString *identifier;
|
|
|
|
NSString *serverName;
|
|
|
|
NSString *severityText;
|
|
|
|
NSString *text;
|
|
|
|
NSDate *timestamp;
|
|
|
|
NSString *type;
|
|
|
|
int duration;
|
|
|
|
int reminder;
|
|
|
|
int severity;
|
2015-11-18 11:25:49 +00:00
|
|
|
BOOL isAlarm;
|
2013-04-11 11:06:20 +00:00
|
|
|
BOOL isClear;
|
|
|
|
}
|
2015-11-18 11:25:49 +00:00
|
|
|
- (NSString*) alarmText;
|
2013-04-11 11:06:20 +00:00
|
|
|
@end
|
|
|
|
@implementation EcAlerterEvent
|
2015-11-18 11:25:49 +00:00
|
|
|
- (NSString*) alarmText
|
|
|
|
{
|
|
|
|
if (NO == isAlarm)
|
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
if (YES == isClear)
|
|
|
|
{
|
|
|
|
return [identifier stringByAppendingString: @"(clear)"];
|
|
|
|
}
|
|
|
|
return [identifier stringByAppendingString: @"(alarm)"];
|
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
- (void) dealloc
|
|
|
|
{
|
|
|
|
RELEASE(hostName);
|
|
|
|
RELEASE(identifier);
|
|
|
|
RELEASE(m);
|
|
|
|
RELEASE(serverName);
|
|
|
|
RELEASE(severityText);
|
|
|
|
RELEASE(text);
|
|
|
|
RELEASE(timestamp);
|
|
|
|
RELEASE(type);
|
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
@end
|
|
|
|
|
2012-02-19 11:59:22 +00:00
|
|
|
static NSMutableString *
|
2013-04-07 11:38:46 +00:00
|
|
|
replaceFields(NSDictionary *fields, NSString *template)
|
2012-02-19 11:59:22 +00:00
|
|
|
{
|
|
|
|
NSMutableString *m;
|
|
|
|
|
2013-04-07 11:38:46 +00:00
|
|
|
m = [[template mutableCopy] autorelease];
|
2012-02-19 11:59:22 +00:00
|
|
|
if (nil != m)
|
|
|
|
{
|
|
|
|
NSEnumerator *e;
|
|
|
|
NSString *k;
|
|
|
|
|
|
|
|
e = [fields keyEnumerator];
|
|
|
|
while (nil != (k = [e nextObject]))
|
|
|
|
{
|
|
|
|
if (NO == [k isEqualToString: @"Replacement"])
|
|
|
|
{
|
|
|
|
NSString *v;
|
|
|
|
|
|
|
|
v = [[fields objectForKey: k] description];
|
|
|
|
k = [NSString stringWithFormat: @"{%@}", k];
|
|
|
|
[m replaceOccurrencesOfString: k
|
|
|
|
withString: v
|
|
|
|
options: NSLiteralSearch
|
|
|
|
range: NSMakeRange(0, [m length])];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
|
|
|
@implementation EcAlerter : NSObject
|
|
|
|
|
2013-04-05 23:20:16 +00:00
|
|
|
- (void) _setEFrom: (NSString*)s
|
|
|
|
{
|
|
|
|
if (nil == s)
|
|
|
|
{
|
|
|
|
/* Can't have a nil sender ... use (generate if needed) default.
|
|
|
|
*/
|
|
|
|
if (nil == eDflt)
|
|
|
|
{
|
|
|
|
eDflt = [[NSString alloc] initWithFormat: @"alerter@%@",
|
|
|
|
[[NSHost currentHost] wellKnownName]];
|
|
|
|
}
|
|
|
|
s = eDflt;
|
|
|
|
}
|
|
|
|
if (s != eFrom && NO == [s isEqual: eFrom])
|
|
|
|
{
|
|
|
|
NSRange r;
|
|
|
|
|
|
|
|
ASSIGNCOPY(eFrom, s);
|
|
|
|
r = [s rangeOfString: @"@"];
|
|
|
|
if (r.length > 0)
|
|
|
|
{
|
|
|
|
s = [s substringFromIndex: NSMaxRange(r)];
|
|
|
|
}
|
|
|
|
ASSIGNCOPY(eBase, s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-06 06:56:02 +00:00
|
|
|
- (void) smtpClient: (GSMimeSMTPClient*)client mimeFailed: (GSMimeDocument*)doc
|
|
|
|
{
|
2013-09-04 08:07:02 +00:00
|
|
|
failEmail++;
|
2013-04-06 06:56:02 +00:00
|
|
|
NSLog(@"Message failed: %@", doc);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) smtpClient: (GSMimeSMTPClient*)client mimeSent: (GSMimeDocument*)doc
|
|
|
|
{
|
2013-09-04 08:07:02 +00:00
|
|
|
sentEmail++;
|
2013-04-06 06:56:02 +00:00
|
|
|
if (YES == debug)
|
|
|
|
{
|
|
|
|
NSLog(@"Message sent: %@", doc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) smtpClient: (GSMimeSMTPClient*)client mimeUnsent: (GSMimeDocument*)doc
|
|
|
|
{
|
2013-09-04 08:07:02 +00:00
|
|
|
failEmail++;
|
2013-04-06 06:56:02 +00:00
|
|
|
NSLog(@"Message dropped on SMTP client shutdown: %@", doc);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (GSMimeSMTPClient*) _smtp
|
|
|
|
{
|
|
|
|
if (nil == smtp)
|
|
|
|
{
|
|
|
|
smtp = [GSMimeSMTPClient new];
|
|
|
|
}
|
2017-08-30 07:56:04 +00:00
|
|
|
[lock lock];
|
2013-04-06 06:56:02 +00:00
|
|
|
if (nil == eFrom)
|
|
|
|
{
|
|
|
|
[self _setEFrom: nil];
|
|
|
|
}
|
|
|
|
if (nil != eHost)
|
|
|
|
{
|
|
|
|
[smtp setHostname: eHost];
|
|
|
|
}
|
|
|
|
if (nil != ePort)
|
|
|
|
{
|
|
|
|
[smtp setPort: ePort];
|
|
|
|
}
|
2017-08-30 07:56:04 +00:00
|
|
|
[lock unlock];
|
2013-04-06 06:56:02 +00:00
|
|
|
[smtp setDelegate: self];
|
|
|
|
return smtp;
|
|
|
|
}
|
|
|
|
|
2012-02-19 11:59:22 +00:00
|
|
|
- (BOOL) configure: (NSNotification*)n
|
|
|
|
{
|
|
|
|
NSUserDefaults *d;
|
|
|
|
NSDictionary *c;
|
2015-02-23 14:57:10 +00:00
|
|
|
BOOL ok;
|
2012-02-19 11:59:22 +00:00
|
|
|
|
|
|
|
d = [EcProc cmdDefaults];
|
|
|
|
c = [d dictionaryForKey: @"Alerter"];
|
2015-02-23 14:57:10 +00:00
|
|
|
ok = [self configureWithDefaults: c];
|
|
|
|
return ok;
|
2013-03-18 17:11:41 +00:00
|
|
|
}
|
2012-02-19 11:59:22 +00:00
|
|
|
|
2013-03-18 17:11:41 +00:00
|
|
|
- (BOOL) configureWithDefaults: (NSDictionary*)c
|
|
|
|
{
|
2013-04-06 06:56:02 +00:00
|
|
|
debug = [[c objectForKey: @"Debug"] boolValue];
|
2015-11-18 11:25:49 +00:00
|
|
|
quiet = [[c objectForKey: @"Quiet"] boolValue];
|
2013-04-06 19:53:54 +00:00
|
|
|
supersede = [[c objectForKey: @"Supersede"] boolValue];
|
2017-08-30 07:56:04 +00:00
|
|
|
[lock lock];
|
2013-04-05 23:20:16 +00:00
|
|
|
[self _setEFrom: [c objectForKey: @"EmailFrom"]];
|
2012-02-19 11:59:22 +00:00
|
|
|
ASSIGNCOPY(eHost, [c objectForKey: @"EmailHost"]);
|
|
|
|
ASSIGNCOPY(ePort, [c objectForKey: @"EmailPort"]);
|
2017-08-30 07:56:04 +00:00
|
|
|
[lock unlock];
|
2013-03-18 17:11:41 +00:00
|
|
|
return [self setRules: [c objectForKey: @"Rules"]];
|
|
|
|
}
|
2012-02-19 11:59:22 +00:00
|
|
|
|
2013-03-28 10:05:36 +00:00
|
|
|
- (BOOL) setRules: (NSArray*)ra
|
2013-03-18 17:11:41 +00:00
|
|
|
{
|
2013-03-28 10:05:36 +00:00
|
|
|
NSMutableArray *r = AUTORELEASE([ra mutableCopy]);
|
2015-02-23 10:55:02 +00:00
|
|
|
NSUInteger i;
|
2013-03-28 10:05:36 +00:00
|
|
|
|
2012-02-19 11:59:22 +00:00
|
|
|
for (i = 0; i < [r count]; i++)
|
|
|
|
{
|
|
|
|
NSMutableDictionary *md;
|
2015-02-23 10:55:02 +00:00
|
|
|
NSObject *obj;
|
2012-02-19 11:59:22 +00:00
|
|
|
NSString *str;
|
|
|
|
Regex *val;
|
|
|
|
|
|
|
|
md = [[r objectAtIndex: i] mutableCopy];
|
|
|
|
[r replaceObjectAtIndex: i withObject: md];
|
|
|
|
[md release];
|
|
|
|
|
|
|
|
str = [md objectForKey: @"Host"];
|
|
|
|
[md removeObjectForKey: @"HostRegex"];
|
|
|
|
if (str != nil)
|
|
|
|
{
|
|
|
|
val = [[Regex alloc] initWithString: str];
|
|
|
|
if (nil == val)
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
[md setObject: val forKey: @"HostRegex"];
|
|
|
|
[val release];
|
|
|
|
}
|
|
|
|
|
|
|
|
str = [md objectForKey: @"Pattern"];
|
|
|
|
[md removeObjectForKey: @"PatternRegex"];
|
|
|
|
if (str != nil)
|
|
|
|
{
|
|
|
|
val = [[Regex alloc] initWithString: str];
|
|
|
|
if (val == nil)
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
[md setObject: val forKey: @"PatternRegex"];
|
|
|
|
RELEASE(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
str = [md objectForKey: @"Server"];
|
|
|
|
[md removeObjectForKey: @"ServerRegex"];
|
|
|
|
if (str != nil)
|
|
|
|
{
|
|
|
|
val = [[Regex alloc] initWithString: str];
|
|
|
|
if (val == nil)
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
[md setObject: val forKey: @"ServerRegex"];
|
|
|
|
RELEASE(val);
|
|
|
|
}
|
|
|
|
|
2013-04-07 10:56:03 +00:00
|
|
|
str = [md objectForKey: @"SeverityText"];
|
|
|
|
[md removeObjectForKey: @"SeverityTextRegex"];
|
|
|
|
if (str != nil)
|
|
|
|
{
|
|
|
|
val = [[Regex alloc] initWithString: str];
|
|
|
|
if (val == nil)
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
[md setObject: val forKey: @"SeverityTextRegex"];
|
|
|
|
RELEASE(val);
|
|
|
|
}
|
|
|
|
|
2012-02-19 11:59:22 +00:00
|
|
|
str = [md objectForKey: @"Extra1"];
|
|
|
|
[md removeObjectForKey: @"Extra1Regex"];
|
|
|
|
if (str != nil)
|
|
|
|
{
|
|
|
|
val = [[Regex alloc] initWithString: str];
|
|
|
|
if (val == nil)
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
[md setObject: val forKey: @"Extra1Regex"];
|
|
|
|
RELEASE(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
str = [md objectForKey: @"Extra2"];
|
|
|
|
[md removeObjectForKey: @"Extra2Regex"];
|
|
|
|
if (str != nil)
|
|
|
|
{
|
|
|
|
val = [[Regex alloc] initWithString: str];
|
|
|
|
if (val == nil)
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
[md setObject: val forKey: @"Extra2Regex"];
|
|
|
|
RELEASE(val);
|
|
|
|
}
|
2013-04-07 10:56:03 +00:00
|
|
|
|
2015-02-23 10:55:02 +00:00
|
|
|
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;
|
|
|
|
}
|
2015-02-23 14:57:10 +00:00
|
|
|
if (1 == c) m = 0;
|
2015-02-23 10:55:02 +00:00
|
|
|
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;
|
|
|
|
}
|
2015-02-23 14:57:10 +00:00
|
|
|
if (1 == c) m = 0;
|
2015-02-23 10:55:02 +00:00
|
|
|
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;
|
|
|
|
}
|
2012-02-19 11:59:22 +00:00
|
|
|
}
|
2017-08-30 07:56:04 +00:00
|
|
|
[lock lock];
|
2012-02-19 11:59:22 +00:00
|
|
|
ASSIGN(rules, r);
|
2017-08-30 07:56:04 +00:00
|
|
|
[lock unlock];
|
2015-05-29 14:30:12 +00:00
|
|
|
if (YES == debug)
|
|
|
|
{
|
2017-08-30 07:56:04 +00:00
|
|
|
NSLog(@"Installed Rules: %@", r);
|
2015-05-29 14:30:12 +00:00
|
|
|
}
|
2012-02-19 11:59:22 +00:00
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
{
|
|
|
|
[[NSNotificationCenter defaultCenter] removeObserver: self];
|
|
|
|
[timer invalidate];
|
|
|
|
[self flushSms];
|
|
|
|
[self flushEmail];
|
|
|
|
[smtp flush: [NSDate dateWithTimeIntervalSinceNow: 30.0]];
|
|
|
|
RELEASE(smtp);
|
|
|
|
RELEASE(email);
|
|
|
|
RELEASE(sms);
|
|
|
|
RELEASE(rules);
|
2017-08-30 07:56:04 +00:00
|
|
|
RELEASE(eBase);
|
|
|
|
RELEASE(eDflt);
|
|
|
|
RELEASE(eFrom);
|
|
|
|
RELEASE(eHost);
|
|
|
|
RELEASE(ePort);
|
|
|
|
RELEASE(lock);
|
2012-02-19 11:59:22 +00:00
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString*) description
|
|
|
|
{
|
2017-08-30 07:56:04 +00:00
|
|
|
NSString *s;
|
|
|
|
|
|
|
|
[lock lock];
|
|
|
|
s = [NSString stringWithFormat: @"%@ -\nConfigured with %u rules\n"
|
2013-09-04 08:07:02 +00:00
|
|
|
@"With SMTP %@:%@ as %@\n"
|
|
|
|
@"Email sent: %"PRIuPTR", fail: %"PRIuPTR", pending:%@\n"
|
|
|
|
@"SMS pending:%@",
|
2013-07-13 07:58:07 +00:00
|
|
|
[super description], (unsigned)[rules count], eHost, ePort,
|
2013-09-04 08:07:02 +00:00
|
|
|
eFrom, sentEmail, failEmail, email, sms];
|
2017-08-30 07:56:04 +00:00
|
|
|
[lock unlock];
|
|
|
|
return s;
|
2012-02-19 11:59:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) flushEmailForAddress: (NSString*)address
|
|
|
|
subject: (NSString*)subject
|
|
|
|
text: (NSString*)text
|
|
|
|
{
|
|
|
|
NS_DURING
|
|
|
|
{
|
2013-04-05 23:20:16 +00:00
|
|
|
GSMimeDocument *doc;
|
|
|
|
|
2012-02-19 11:59:22 +00:00
|
|
|
doc = AUTORELEASE([GSMimeDocument new]);
|
2013-04-08 15:50:32 +00:00
|
|
|
[doc setHeader: @"Subject" value: subject parameters: nil];
|
|
|
|
[doc setHeader: @"To" value: address parameters: nil];
|
2012-02-19 11:59:22 +00:00
|
|
|
[doc setContent: text type: @"text/plain" name: nil];
|
2017-08-30 07:56:04 +00:00
|
|
|
[lock lock];
|
|
|
|
[doc setHeader: @"From" value: eFrom parameters: nil];
|
|
|
|
[lock unlock];
|
2013-04-06 06:56:02 +00:00
|
|
|
[[self _smtp] send: doc];
|
2012-02-19 11:59:22 +00:00
|
|
|
}
|
|
|
|
NS_HANDLER
|
|
|
|
{
|
|
|
|
NSLog(@"Problem flushing email for address: %@, subject: %@, %@",
|
|
|
|
address, subject, localException);
|
|
|
|
}
|
|
|
|
NS_ENDHANDLER
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) flushEmail
|
|
|
|
{
|
|
|
|
NSDictionary *destinations;
|
|
|
|
|
|
|
|
NS_DURING
|
|
|
|
{
|
|
|
|
if ((destinations = email) != nil)
|
|
|
|
{
|
|
|
|
NSEnumerator *addressEnumerator = [destinations keyEnumerator];
|
|
|
|
NSString *address;
|
|
|
|
|
|
|
|
DESTROY(email);
|
|
|
|
while ((address = [addressEnumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
NSDictionary *items = [destinations objectForKey: address];
|
|
|
|
NSEnumerator *itemEnumerator = [items keyEnumerator];
|
|
|
|
NSString *subject;
|
|
|
|
|
|
|
|
while ((subject = [itemEnumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
NSString *text = [items objectForKey: subject];
|
|
|
|
|
|
|
|
[self flushEmailForAddress: address
|
|
|
|
subject: subject
|
|
|
|
text: text];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
NS_HANDLER
|
|
|
|
{
|
|
|
|
NSLog(@"Problem flushing email: %@", localException);
|
|
|
|
}
|
|
|
|
NS_ENDHANDLER
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) flushSms
|
|
|
|
{
|
2013-09-04 08:07:02 +00:00
|
|
|
[sms removeAllObjects];
|
2012-02-19 11:59:22 +00:00
|
|
|
}
|
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
- (void) applyRules: (NSArray*)rulesArray
|
|
|
|
toEvent: (EcAlerterEvent*)event
|
2012-02-19 11:59:22 +00:00
|
|
|
{
|
2015-02-23 10:55:02 +00:00
|
|
|
NSAutoreleasePool *pool = nil;
|
|
|
|
NSTimeZone *tz = nil;
|
|
|
|
BOOL found = NO;
|
|
|
|
NSCalendarDate *now = [NSCalendarDate date];
|
|
|
|
NSUInteger minuteOfDay = 0;
|
|
|
|
NSUInteger dayOfWeek = 0;
|
|
|
|
NSUInteger i;
|
2013-04-11 11:06:20 +00:00
|
|
|
|
|
|
|
for (i = 0; i < [rulesArray count]; i++)
|
2013-03-28 10:05:36 +00:00
|
|
|
{
|
2015-02-23 10:55:02 +00:00
|
|
|
NSDictionary *times;
|
2013-04-11 11:06:20 +00:00
|
|
|
NSDictionary *d;
|
|
|
|
NSString *match = nil;
|
|
|
|
Regex *e;
|
|
|
|
NSString *s;
|
|
|
|
id o;
|
2013-03-28 10:05:36 +00:00
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
RELEASE(pool);
|
|
|
|
pool = [NSAutoreleasePool new];
|
|
|
|
d = [rulesArray objectAtIndex: i];
|
2013-03-28 10:05:36 +00:00
|
|
|
|
2015-02-23 10:55:02 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
s = [d objectForKey: @"Tagged"];
|
|
|
|
if (s != nil && NO == [s isEqual: [event->m objectForKey: @"Tag"]])
|
2013-03-28 10:05:36 +00:00
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
continue; // Not a match.
|
2013-03-28 10:05:36 +00:00
|
|
|
}
|
2013-04-07 10:56:03 +00:00
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
s = [d objectForKey: @"Type"];
|
|
|
|
if (s != nil && [s isEqualToString: event->type] == NO)
|
2013-04-07 10:56:03 +00:00
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
continue; // Not a match.
|
2013-04-07 10:56:03 +00:00
|
|
|
}
|
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
/* The next set are performed only for alarms,
|
|
|
|
* since a non-alarm can never match them.
|
|
|
|
*/
|
|
|
|
if (event->reminder >= 0)
|
2013-03-28 10:05:36 +00:00
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
if (event->reminder > 0 && NO == event->isClear)
|
2013-04-09 13:12:59 +00:00
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
/* This is an alarm reminder (neither the initial alarm
|
|
|
|
* nor the clear), so we check the ReminderInterval.
|
|
|
|
* In order for a match to occur, the ReminderInterval
|
|
|
|
* must be set and must match the number of the reminder
|
|
|
|
* using division modulo the reminder interval value.
|
|
|
|
* NB, unlike other patterns, the absence of this one
|
|
|
|
* implies a match failure!
|
|
|
|
*/
|
|
|
|
s = [d objectForKey: @"ReminderInterval"];
|
|
|
|
if (nil == s || (event->reminder % [s intValue]))
|
|
|
|
{
|
|
|
|
continue; // Not a match.
|
|
|
|
}
|
2013-04-09 13:12:59 +00:00
|
|
|
}
|
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
s = [d objectForKey: @"DurationAbove"];
|
|
|
|
if (s != nil && event->duration <= [s intValue])
|
2013-03-28 10:05:36 +00:00
|
|
|
{
|
|
|
|
continue; // Not a match.
|
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
s = [d objectForKey: @"DurationBelow"];
|
|
|
|
if (s != nil && event->duration >= [s intValue])
|
2013-04-07 10:56:03 +00:00
|
|
|
{
|
|
|
|
continue; // Not a match.
|
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
s = [d objectForKey: @"ReminderAbove"];
|
|
|
|
if (s != nil && event->reminder <= [s intValue])
|
2013-04-08 12:09:58 +00:00
|
|
|
{
|
|
|
|
continue; // Not a match.
|
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
s = [d objectForKey: @"ReminderBelow"];
|
|
|
|
if (s != nil && event->reminder >= [s intValue])
|
2013-03-28 10:05:36 +00:00
|
|
|
{
|
|
|
|
continue; // Not a match.
|
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
e = [d objectForKey: @"SeverityTextRegex"];
|
|
|
|
if (e != nil && [e match: event->severityText] == nil)
|
2013-03-28 10:05:36 +00:00
|
|
|
{
|
|
|
|
continue; // Not a match.
|
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
|
|
|
|
s = [d objectForKey: @"SeverityCode"];
|
|
|
|
if (s != nil && [s intValue] != event->severity)
|
2013-03-28 10:05:36 +00:00
|
|
|
{
|
|
|
|
continue; // Not a match.
|
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
}
|
2013-03-28 10:05:36 +00:00
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
e = [d objectForKey: @"ServerRegex"];
|
|
|
|
if (e != nil && [e match: event->serverName] == nil)
|
|
|
|
{
|
|
|
|
continue; // Not a match.
|
|
|
|
}
|
|
|
|
e = [d objectForKey: @"HostRegex"];
|
|
|
|
if (e != nil && [e match: event->hostName] == nil)
|
|
|
|
{
|
|
|
|
continue; // Not a match.
|
|
|
|
}
|
2013-03-28 10:05:36 +00:00
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
e = [d objectForKey: @"PatternRegex"];
|
|
|
|
if (nil != e)
|
|
|
|
{
|
|
|
|
[event->m removeObjectForKey: @"Match"];
|
|
|
|
if (nil == (match = [e match: event->text]))
|
2013-03-28 10:05:36 +00:00
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
continue; // Not a match.
|
2013-03-28 10:05:36 +00:00
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
[event->m setObject: match forKey: @"Match"];
|
|
|
|
}
|
2013-03-28 10:05:36 +00:00
|
|
|
|
2014-09-02 09:19:29 +00:00
|
|
|
|
|
|
|
found = YES;
|
|
|
|
if (YES == debug)
|
|
|
|
{
|
|
|
|
NSLog(@"Rule %u matched %@ with %@", (unsigned)i, d, event->m);
|
|
|
|
}
|
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
/*
|
|
|
|
* If the Extra1 or Extra2 patterns are matched,
|
|
|
|
* The matching strings are made available for
|
|
|
|
* substitution into the replacement message.
|
|
|
|
*/
|
|
|
|
e = [d objectForKey: @"Extra1Regex"];
|
|
|
|
if (nil != e)
|
|
|
|
{
|
|
|
|
[event->m removeObjectForKey: @"Extra1"];
|
|
|
|
if (nil == (match = [e match: event->text]))
|
2013-03-28 10:05:36 +00:00
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
[event->m setObject: match forKey: @"Extra1"];
|
2013-03-28 10:05:36 +00:00
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
}
|
2013-03-28 10:05:36 +00:00
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
e = [d objectForKey: @"Extra2Regex"];
|
|
|
|
if (nil != e)
|
|
|
|
{
|
|
|
|
[event->m removeObjectForKey: @"Extra2"];
|
|
|
|
if (nil != (match = [e match: event->text]))
|
2013-04-07 10:56:03 +00:00
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
[event->m setObject: match forKey: @"Extra2"];
|
2013-04-07 10:56:03 +00:00
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
}
|
2013-04-07 10:56:03 +00:00
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
s = [d objectForKey: @"Rewrite"];
|
|
|
|
if (nil != s)
|
|
|
|
{
|
|
|
|
s = replaceFields(event->m, s);
|
|
|
|
[event->m setObject: s forKey: @"Message"];
|
|
|
|
}
|
2013-04-09 13:12:59 +00:00
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
s = [d objectForKey: @"Subject"];
|
|
|
|
if (s != nil)
|
|
|
|
{
|
|
|
|
s = replaceFields(event->m, s);
|
|
|
|
[event->m setObject: s forKey: @"Subject"];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the tag for this event if necessary ... done *after*
|
|
|
|
* all matching, but before sending out the alerts.
|
|
|
|
*/
|
|
|
|
if (nil != [d objectForKey: @"Tag"])
|
|
|
|
{
|
|
|
|
NSString *s = replaceFields(event->m, [d objectForKey: @"Tag"]);
|
|
|
|
|
|
|
|
[event->m setObject: s forKey: @"Tag"];
|
|
|
|
}
|
2013-03-28 10:05:36 +00:00
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
NS_DURING
|
|
|
|
{
|
|
|
|
o = [d objectForKey: @"Log"];
|
|
|
|
if ([o isKindOfClass: [NSString class]] == YES)
|
2013-03-28 10:05:36 +00:00
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
if ([o hasPrefix: @"("])
|
2013-03-28 10:05:36 +00:00
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
o = [(NSString*)o propertyList];
|
2013-03-28 10:05:36 +00:00
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
else
|
2013-03-28 10:05:36 +00:00
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
o = [NSArray arrayWithObject: o];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (o != nil)
|
|
|
|
{
|
|
|
|
NSString *s = [d objectForKey: @"LogReplacement"];
|
2013-04-07 10:56:03 +00:00
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
if (nil == s)
|
|
|
|
{
|
|
|
|
s = [d objectForKey: @"Replacement"];
|
2013-04-07 10:56:03 +00:00
|
|
|
if (nil == s)
|
2013-03-28 10:05:36 +00:00
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
s = @"{Message}";
|
2013-03-28 10:05:36 +00:00
|
|
|
}
|
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
[event->m setObject: s forKey: @"Replacement"];
|
|
|
|
[self log: event->m
|
|
|
|
identifier: event->identifier
|
|
|
|
isClear: event->isClear
|
|
|
|
to: o];
|
2013-03-28 10:05:36 +00:00
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
}
|
|
|
|
NS_HANDLER
|
|
|
|
{
|
2015-02-21 05:03:59 +00:00
|
|
|
NSLog(@"Exception handling log for rule: %@",
|
2013-04-11 11:06:20 +00:00
|
|
|
localException);
|
|
|
|
}
|
|
|
|
NS_ENDHANDLER
|
|
|
|
[event->m removeObjectForKey: @"Replacement"];
|
2013-03-28 10:05:36 +00:00
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
NS_DURING
|
|
|
|
{
|
|
|
|
o = [d objectForKey: @"Email"];
|
|
|
|
if ([o isKindOfClass: [NSString class]] == YES)
|
2013-03-28 10:05:36 +00:00
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
if ([o hasPrefix: @"("])
|
2013-03-28 10:05:36 +00:00
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
o = [(NSString*)o propertyList];
|
2013-03-28 10:05:36 +00:00
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
else
|
2013-03-28 10:05:36 +00:00
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
o = [NSArray arrayWithObject: o];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (o != nil)
|
|
|
|
{
|
|
|
|
NSString *s;
|
2013-03-28 10:05:36 +00:00
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
s = [d objectForKey: @"EmailReplacement"];
|
|
|
|
if (nil == s)
|
|
|
|
{
|
|
|
|
s = [d objectForKey: @"Replacement"];
|
2013-04-07 10:56:03 +00:00
|
|
|
if (nil == s)
|
2013-03-28 10:05:36 +00:00
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
/* Full details. */
|
|
|
|
s = @"{Server}({Host}): {Timestamp} {Type}"
|
|
|
|
@" - {Message}";
|
2013-03-28 10:05:36 +00:00
|
|
|
}
|
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
[event->m setObject: s forKey: @"Replacement"];
|
2015-11-18 11:25:49 +00:00
|
|
|
if (YES == event->isAlarm && NO == quiet)
|
|
|
|
{
|
|
|
|
NSLog(@"Send Email for %@ to %@", [event alarmText], o);
|
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
[self mail: event->m
|
|
|
|
identifier: event->identifier
|
|
|
|
isClear: event->isClear
|
|
|
|
to: o];
|
2013-03-28 10:05:36 +00:00
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
}
|
|
|
|
NS_HANDLER
|
|
|
|
{
|
|
|
|
NSLog(@"Exception handling Email send for rule: %@",
|
|
|
|
localException);
|
|
|
|
}
|
|
|
|
NS_ENDHANDLER
|
|
|
|
[event->m removeObjectForKey: @"Replacement"];
|
2013-03-28 10:05:36 +00:00
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
NS_DURING
|
|
|
|
{
|
|
|
|
o = [d objectForKey: @"Threaded"];
|
|
|
|
if ([o isKindOfClass: [NSString class]] == YES)
|
2013-04-08 15:50:32 +00:00
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
if ([o hasPrefix: @"("])
|
2013-04-08 15:50:32 +00:00
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
o = [(NSString*)o propertyList];
|
2013-04-08 15:50:32 +00:00
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
else
|
2013-04-08 15:50:32 +00:00
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
o = [NSArray arrayWithObject: o];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (o != nil)
|
|
|
|
{
|
|
|
|
NSString *s;
|
2013-04-08 15:50:32 +00:00
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
if (event->reminder > 0)
|
|
|
|
{
|
|
|
|
NSString *s;
|
2013-04-08 15:50:32 +00:00
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
/* Pass the reminder value to the email code so it
|
|
|
|
* can generate In-Reply-To and References headers
|
|
|
|
* for threading.
|
|
|
|
*/
|
|
|
|
s = [NSString stringWithFormat: @"%d", event->reminder];
|
|
|
|
[event->m setObject: s forKey: @"EmailThreading"];
|
|
|
|
}
|
2013-04-08 15:50:32 +00:00
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
s = [d objectForKey: @"EmailReplacement"];
|
|
|
|
if (nil == s)
|
|
|
|
{
|
|
|
|
s = [d objectForKey: @"Replacement"];
|
2013-04-08 15:50:32 +00:00
|
|
|
if (nil == s)
|
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
/* Full details. */
|
|
|
|
s = @"{Server}({Host}): {Timestamp} {Type}"
|
|
|
|
@" - {Message}";
|
2013-04-08 15:50:32 +00:00
|
|
|
}
|
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
[event->m setObject: s forKey: @"Replacement"];
|
2015-11-18 11:25:49 +00:00
|
|
|
if (YES == event->isAlarm && NO == quiet)
|
|
|
|
{
|
|
|
|
NSLog(@"Send Email for %@ to %@", [event alarmText], o);
|
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
[self mail: event->m
|
|
|
|
identifier: event->identifier
|
|
|
|
isClear: event->isClear
|
|
|
|
to: o];
|
2013-04-08 15:50:32 +00:00
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
}
|
|
|
|
NS_HANDLER
|
|
|
|
{
|
|
|
|
NSLog(@"Exception handling Email send for rule: %@",
|
|
|
|
localException);
|
|
|
|
}
|
|
|
|
NS_ENDHANDLER
|
|
|
|
[event->m removeObjectForKey: @"Replacement"];
|
|
|
|
[event->m removeObjectForKey: @"ReminderInterval"];
|
2013-04-08 15:50:32 +00:00
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
NS_DURING
|
|
|
|
{
|
|
|
|
o = [d objectForKey: @"Sms"];
|
|
|
|
if ([o isKindOfClass: [NSString class]] == YES)
|
2013-03-28 10:05:36 +00:00
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
if ([o hasPrefix: @"("])
|
2013-03-28 10:05:36 +00:00
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
o = [(NSString*)o propertyList];
|
2013-03-28 10:05:36 +00:00
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
else
|
2013-03-28 10:05:36 +00:00
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
o = [NSArray arrayWithObject: o];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (o != nil)
|
|
|
|
{
|
|
|
|
NSString *s = [d objectForKey: @"SmsReplacement"];
|
2013-04-07 10:56:03 +00:00
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
if (nil == s)
|
|
|
|
{
|
|
|
|
s = [d objectForKey: @"Replacement"];
|
2013-04-07 10:56:03 +00:00
|
|
|
if (nil == s)
|
2013-03-28 10:05:36 +00:00
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
/* Use few spaces so that more of the
|
|
|
|
* message fits into an Sms. */
|
|
|
|
s = @"{Server}({Host}):{Timestamp} {Type}-{Message}";
|
2013-03-28 10:05:36 +00:00
|
|
|
}
|
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
[event->m setObject: s forKey: @"Replacement"];
|
2015-11-18 11:25:49 +00:00
|
|
|
if (YES == event->isAlarm && NO == quiet)
|
|
|
|
{
|
|
|
|
NSLog(@"Send SMS for %@ to %@", [event alarmText], o);
|
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
[self sms: event->m
|
|
|
|
identifier: event->identifier
|
|
|
|
isClear: event->isClear
|
|
|
|
to: o];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
NS_HANDLER
|
|
|
|
{
|
|
|
|
NSLog(@"Exception handling Sms send for rule: %@",
|
|
|
|
localException);
|
|
|
|
}
|
|
|
|
NS_ENDHANDLER
|
|
|
|
[event->m removeObjectForKey: @"Replacement"];
|
|
|
|
|
|
|
|
s = [d objectForKey: @"Flush"];
|
|
|
|
if (s != nil)
|
|
|
|
{
|
|
|
|
if ([s caseInsensitiveCompare: @"Email"] == NSOrderedSame)
|
|
|
|
{
|
|
|
|
[self flushEmail];
|
2013-03-28 10:05:36 +00:00
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
else if ([s caseInsensitiveCompare: @"Sms"] == NSOrderedSame)
|
2013-03-28 10:05:36 +00:00
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
[self flushSms];
|
2013-03-28 10:05:36 +00:00
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
else if ([s boolValue] == YES)
|
2013-03-28 10:05:36 +00:00
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
[self flushSms];
|
|
|
|
[self flushEmail];
|
2013-03-28 10:05:36 +00:00
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
}
|
2013-03-28 10:05:36 +00:00
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
if ([[d objectForKey: @"Stop"] boolValue] == YES)
|
|
|
|
{
|
2015-11-18 11:25:49 +00:00
|
|
|
if (YES == event->isAlarm && NO == quiet)
|
|
|
|
{
|
|
|
|
NSLog(@"Stop %@ with %@", [event alarmText], d);
|
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
break; // Don't want to perform any more matches.
|
|
|
|
}
|
|
|
|
}
|
2014-09-02 09:19:29 +00:00
|
|
|
if (NO == found)
|
|
|
|
{
|
2015-11-18 11:25:49 +00:00
|
|
|
if (YES == event->isAlarm && NO == quiet)
|
|
|
|
{
|
|
|
|
NSLog(@"No match of %@ with %@", [event alarmText], rulesArray);
|
|
|
|
}
|
|
|
|
else if (YES == debug)
|
2014-09-02 09:19:29 +00:00
|
|
|
{
|
|
|
|
NSLog(@"No match of %@ with %@", event->m, rulesArray);
|
|
|
|
}
|
|
|
|
}
|
2015-02-23 10:55:02 +00:00
|
|
|
DESTROY(tz);
|
2013-04-11 11:06:20 +00:00
|
|
|
RELEASE(pool);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) handleEvent: (NSString*)text
|
|
|
|
withHost: (NSString*)hostName
|
|
|
|
andServer: (NSString*)serverName
|
|
|
|
timestamp: (NSDate*)timestamp
|
|
|
|
identifier: (NSString*)identifier
|
2013-04-12 09:47:08 +00:00
|
|
|
alarm: (EcAlarm*)alarm
|
2013-04-11 11:06:20 +00:00
|
|
|
reminder: (int)reminder
|
|
|
|
{
|
|
|
|
NS_DURING
|
|
|
|
{
|
|
|
|
NSMutableDictionary *m;
|
2013-04-12 09:47:08 +00:00
|
|
|
NSString *str;
|
2017-08-30 07:56:04 +00:00
|
|
|
NSArray *array;
|
2013-04-12 09:47:08 +00:00
|
|
|
EcAlerterEvent *event;
|
2013-04-11 11:06:20 +00:00
|
|
|
|
2013-04-12 09:47:08 +00:00
|
|
|
event = AUTORELEASE([EcAlerterEvent new]);
|
2013-04-11 11:06:20 +00:00
|
|
|
ASSIGN(event->text, text);
|
|
|
|
ASSIGN(event->hostName, hostName);
|
|
|
|
ASSIGN(event->serverName, serverName);
|
|
|
|
ASSIGN(event->timestamp, timestamp);
|
|
|
|
ASSIGN(event->identifier, identifier);
|
|
|
|
|
2013-04-12 09:47:08 +00:00
|
|
|
if (nil == alarm)
|
2013-04-11 11:06:20 +00:00
|
|
|
{
|
2013-04-12 09:47:08 +00:00
|
|
|
event->severity = EcAlarmSeverityIndeterminate;
|
2013-04-12 11:13:02 +00:00
|
|
|
event->severityText = @"";
|
2015-11-18 11:25:49 +00:00
|
|
|
event->isAlarm = NO;
|
2013-04-12 09:47:08 +00:00
|
|
|
event->isClear = NO;
|
|
|
|
if (nil != identifier)
|
2013-03-28 10:05:36 +00:00
|
|
|
{
|
2013-04-12 09:47:08 +00:00
|
|
|
event->type = @"Alert";
|
2013-04-11 11:06:20 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-04-12 09:47:08 +00:00
|
|
|
event->type = @"Error";
|
2013-03-28 10:05:36 +00:00
|
|
|
}
|
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
else
|
|
|
|
{
|
2013-04-12 09:47:08 +00:00
|
|
|
event->severity = [alarm perceivedSeverity];
|
|
|
|
ASSIGN(event->severityText,
|
|
|
|
[EcAlarm stringFromSeverity: event->severity]);
|
2015-11-18 11:25:49 +00:00
|
|
|
event->isAlarm = YES;
|
2013-04-12 09:47:08 +00:00
|
|
|
if ([@"Clear" isEqual: [alarm extra]])
|
|
|
|
{
|
|
|
|
event->isClear = YES;
|
|
|
|
event->type = @"Clear";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
event->isClear = NO;
|
|
|
|
event->type = @"Alarm";
|
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
}
|
2013-04-12 09:47:08 +00:00
|
|
|
event->reminder = reminder;
|
|
|
|
event->duration = (0.0 - [timestamp timeIntervalSinceNow]) / 60.0;
|
2013-04-11 11:06:20 +00:00
|
|
|
|
|
|
|
m = event->m = [[NSMutableDictionary alloc] initWithCapacity: 20];
|
|
|
|
[m setObject: event->serverName forKey: @"Server"];
|
|
|
|
[m setObject: event->hostName forKey: @"Host"];
|
|
|
|
[m setObject: event->type forKey: @"Type"];
|
|
|
|
[m setObject: [NSString stringWithFormat: @"%d", event->severity]
|
|
|
|
forKey: @"SeverityCode"];
|
|
|
|
[m setObject: event->severityText forKey: @"SeverityText"];
|
|
|
|
[m setObject: [event->timestamp description] forKey: @"Timestamp"];
|
|
|
|
if (event->reminder >= 0)
|
|
|
|
{
|
|
|
|
[m setObject: [NSString stringWithFormat: @"%d", event->reminder]
|
|
|
|
forKey: @"Reminder"];
|
|
|
|
}
|
2013-04-12 09:47:08 +00:00
|
|
|
/* If the alarm has a responsible person/entity email address set,
|
|
|
|
* make it available.
|
|
|
|
*/
|
|
|
|
str = [[alarm userInfo] objectForKey: @"ResponsibleEmail"];
|
|
|
|
if (nil != str)
|
|
|
|
{
|
|
|
|
[m setObject: str forKey: @"ResponsibleEmail"];
|
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
if ([event->identifier length] > 0)
|
|
|
|
{
|
|
|
|
[m setObject: event->identifier forKey: @"Identifier"];
|
|
|
|
}
|
|
|
|
[m setObject: [NSString stringWithFormat: @"%d", event->duration]
|
|
|
|
forKey: @"Duration"];
|
|
|
|
[m setObject: [NSString stringWithFormat: @"%d", event->duration / 60]
|
|
|
|
forKey: @"Hours"];
|
|
|
|
[m setObject: [NSString stringWithFormat: @"%02d", event->duration % 60]
|
|
|
|
forKey: @"Minutes"];
|
|
|
|
[m setObject: event->text forKey: @"Message"];
|
|
|
|
[m setObject: event->text forKey: @"Original"];
|
|
|
|
|
2015-11-18 11:25:49 +00:00
|
|
|
if (YES == event->isAlarm && NO == quiet)
|
|
|
|
{
|
|
|
|
NSLog(@"Handling %@ ... %@", [event alarmText], alarm);
|
|
|
|
}
|
2017-08-30 07:56:04 +00:00
|
|
|
[lock lock];
|
|
|
|
array = RETAIN(rules);
|
|
|
|
[lock unlock];
|
|
|
|
[self applyRules: AUTORELEASE(rules) toEvent: event];
|
2013-03-28 10:05:36 +00:00
|
|
|
}
|
|
|
|
NS_HANDLER
|
|
|
|
{
|
|
|
|
NSLog(@"Problem in handleInfo:'%@' ... %@", text, localException);
|
|
|
|
}
|
|
|
|
NS_ENDHANDLER
|
|
|
|
}
|
2012-02-19 11:59:22 +00:00
|
|
|
|
2013-03-28 10:05:36 +00:00
|
|
|
- (void) handleInfo: (NSString*)str
|
|
|
|
{
|
2012-02-19 11:59:22 +00:00
|
|
|
NS_DURING
|
|
|
|
{
|
2013-03-28 10:05:36 +00:00
|
|
|
NSArray *a;
|
|
|
|
NSUInteger i;
|
|
|
|
|
2012-02-19 11:59:22 +00:00
|
|
|
a = [str componentsSeparatedByString: @"\n"];
|
|
|
|
for (i = 0; i < [a count]; i++)
|
|
|
|
{
|
|
|
|
NSString *inf = [a objectAtIndex: i];
|
|
|
|
NSRange r;
|
2013-04-07 10:56:03 +00:00
|
|
|
NSCalendarDate *timestamp;
|
2012-02-19 11:59:22 +00:00
|
|
|
NSString *serverName;
|
|
|
|
NSString *hostName;
|
2013-03-28 10:05:36 +00:00
|
|
|
BOOL immediate;
|
2012-02-19 11:59:22 +00:00
|
|
|
unsigned pos;
|
|
|
|
|
|
|
|
str = inf;
|
|
|
|
if ([str length] == 0)
|
|
|
|
{
|
|
|
|
continue; // Nothing to do
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Record format is -
|
|
|
|
* serverName(hostName): timestamp Alert - message
|
|
|
|
* or
|
|
|
|
* serverName(hostName): timestamp Error - message
|
|
|
|
*/
|
|
|
|
r = [str rangeOfString: @":"];
|
|
|
|
if (r.length == 0)
|
|
|
|
{
|
|
|
|
continue; // Not an alert or error
|
|
|
|
}
|
|
|
|
serverName = [str substringToIndex: r.location];
|
|
|
|
str = [str substringFromIndex: NSMaxRange(r) + 1];
|
|
|
|
r = [serverName rangeOfString: @"("];
|
|
|
|
if (r.length == 0)
|
|
|
|
{
|
|
|
|
continue; // Not an alert or error
|
|
|
|
}
|
|
|
|
pos = NSMaxRange(r);
|
|
|
|
hostName = [serverName substringWithRange:
|
|
|
|
NSMakeRange(pos, [serverName length] - pos - 1)];
|
|
|
|
serverName = [serverName substringToIndex: r.location];
|
|
|
|
|
|
|
|
r = [str rangeOfString: @" Alert - "];
|
|
|
|
if (r.length == 0)
|
|
|
|
{
|
|
|
|
r = [str rangeOfString: @" Error - "];
|
|
|
|
if (r.length == 0)
|
|
|
|
{
|
|
|
|
continue; // Not an alert or error
|
|
|
|
}
|
2013-03-28 10:05:36 +00:00
|
|
|
immediate = NO;
|
2012-02-19 11:59:22 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-03-28 10:05:36 +00:00
|
|
|
immediate = YES;
|
2012-02-19 11:59:22 +00:00
|
|
|
}
|
2013-04-07 10:56:03 +00:00
|
|
|
timestamp = [NSCalendarDate
|
|
|
|
dateWithString: [str substringToIndex: r.location]
|
2015-03-19 21:11:55 +00:00
|
|
|
calendarFormat: @"%Y-%m-%d %H:%M:%S.%F %z"];
|
|
|
|
if (nil == timestamp)
|
|
|
|
{
|
|
|
|
/* Old style.
|
|
|
|
*/
|
|
|
|
timestamp = [NSCalendarDate
|
|
|
|
dateWithString: [str substringToIndex: r.location]
|
|
|
|
calendarFormat: @"%Y-%m-%d %H:%M:%S %z"];
|
|
|
|
}
|
2012-02-19 11:59:22 +00:00
|
|
|
|
|
|
|
str = [str substringFromIndex: NSMaxRange(r)];
|
|
|
|
|
2013-03-28 10:05:36 +00:00
|
|
|
[self handleEvent: str
|
|
|
|
withHost: hostName
|
|
|
|
andServer: serverName
|
|
|
|
timestamp: timestamp
|
2013-04-05 13:50:10 +00:00
|
|
|
identifier: (YES == immediate) ? (id)@"" : (id)nil
|
2013-04-12 09:47:08 +00:00
|
|
|
alarm: nil
|
2013-04-08 10:23:40 +00:00
|
|
|
reminder: -1];
|
2012-02-19 11:59:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
NS_HANDLER
|
|
|
|
{
|
|
|
|
NSLog(@"Problem in handleInfo:'%@' ... %@", str, localException);
|
|
|
|
}
|
|
|
|
NS_ENDHANDLER
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id) init
|
|
|
|
{
|
|
|
|
if (nil != (self = [super init]))
|
|
|
|
{
|
2017-08-30 07:56:04 +00:00
|
|
|
lock = [NSLock new];
|
2012-02-19 11:59:22 +00:00
|
|
|
timer = [NSTimer scheduledTimerWithTimeInterval: 240.0
|
|
|
|
target: self
|
|
|
|
selector: @selector(timeout:)
|
|
|
|
userInfo: nil
|
|
|
|
repeats: YES];
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
addObserver: self
|
|
|
|
selector: @selector(configure:)
|
|
|
|
name: NSUserDefaultsDidChangeNotification
|
|
|
|
object: [NSUserDefaults standardUserDefaults]];
|
2012-03-15 10:22:41 +00:00
|
|
|
[self configure: nil];
|
2012-02-19 11:59:22 +00:00
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2013-04-05 13:50:10 +00:00
|
|
|
- (void) log: (NSMutableDictionary*)m
|
|
|
|
identifier: (NSString*)identifier
|
|
|
|
isClear: (BOOL)isClear
|
|
|
|
to: (NSArray*)destinations
|
2012-02-19 11:59:22 +00:00
|
|
|
{
|
|
|
|
NSEnumerator *e = [destinations objectEnumerator];
|
|
|
|
NSString *d;
|
|
|
|
NSString *s;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Perform {field-name} substitutions ...
|
|
|
|
*/
|
2013-04-07 11:38:46 +00:00
|
|
|
s = replaceFields(m, [m objectForKey: @"Replacement"]);
|
2012-02-19 11:59:22 +00:00
|
|
|
while ((d = [e nextObject]) != nil)
|
|
|
|
{
|
2015-09-30 12:30:55 +00:00
|
|
|
d = [d lastPathComponent];
|
2012-02-19 11:59:22 +00:00
|
|
|
[[EcProc cmdLogFile: d] printf: @"%@\n", s];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-05 13:50:10 +00:00
|
|
|
- (void) mail: (NSMutableDictionary*)m
|
|
|
|
identifier: (NSString*)identifier
|
|
|
|
isClear: (BOOL)isClear
|
|
|
|
to: (NSArray*)destinations
|
2012-02-19 11:59:22 +00:00
|
|
|
{
|
|
|
|
NSEnumerator *e = [destinations objectEnumerator];
|
|
|
|
NSString *d;
|
2013-04-05 23:20:16 +00:00
|
|
|
NSString *text;
|
|
|
|
NSString *subject;
|
2012-02-19 11:59:22 +00:00
|
|
|
|
2013-04-07 11:38:46 +00:00
|
|
|
/*
|
|
|
|
* Perform {field-name} substitutions ...
|
|
|
|
*/
|
|
|
|
text = replaceFields(m, [m objectForKey: @"Replacement"]);
|
|
|
|
|
2013-04-05 23:20:16 +00:00
|
|
|
subject = [m objectForKey: @"Subject"];
|
|
|
|
if (nil == subject)
|
2012-02-19 11:59:22 +00:00
|
|
|
{
|
2013-04-05 23:20:16 +00:00
|
|
|
if ([identifier length] > 0)
|
|
|
|
{
|
|
|
|
if (YES == isClear)
|
|
|
|
{
|
|
|
|
subject = [NSString stringWithFormat: @"Clear %@", identifier];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
subject = [NSString stringWithFormat: @"Alarm %@", identifier];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
subject = @"system alert";
|
|
|
|
}
|
2012-02-19 11:59:22 +00:00
|
|
|
}
|
|
|
|
|
2013-04-05 23:20:16 +00:00
|
|
|
/* If we need to send immediately, don't buffer the message.
|
|
|
|
*/
|
|
|
|
if (nil != identifier)
|
2012-02-19 11:59:22 +00:00
|
|
|
{
|
2013-04-05 23:20:16 +00:00
|
|
|
GSMimeDocument *doc;
|
2017-08-30 07:56:04 +00:00
|
|
|
NSString *base;
|
2012-02-19 11:59:22 +00:00
|
|
|
|
2013-04-06 06:56:02 +00:00
|
|
|
[self _smtp];
|
2013-04-05 23:20:16 +00:00
|
|
|
doc = AUTORELEASE([GSMimeDocument new]);
|
2013-04-08 15:50:32 +00:00
|
|
|
[doc setHeader: @"Subject" value: subject parameters: nil];
|
2013-04-05 23:20:16 +00:00
|
|
|
[doc setContent: text type: @"text/plain" name: nil];
|
2017-08-30 07:56:04 +00:00
|
|
|
[lock lock];
|
2013-04-08 15:50:32 +00:00
|
|
|
[doc setHeader: @"From" value: eFrom parameters: nil];
|
2017-08-30 07:56:04 +00:00
|
|
|
base = RETAIN(eBase);
|
|
|
|
[lock unlock];
|
|
|
|
AUTORELEASE(base);
|
2013-04-05 23:20:16 +00:00
|
|
|
|
|
|
|
if ([identifier length] > 0)
|
|
|
|
{
|
|
|
|
NSString *mID;
|
2013-04-11 11:06:20 +00:00
|
|
|
int threadID;
|
2013-04-05 23:20:16 +00:00
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
threadID = [[m objectForKey: @"EmailThreading"] intValue];
|
|
|
|
if (threadID > 0)
|
2013-04-08 15:50:32 +00:00
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
NSString *rep;
|
|
|
|
NSMutableString *ref;
|
2013-04-08 15:50:32 +00:00
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
rep = [NSString stringWithFormat: @"<alrm%@@%@>",
|
2017-08-30 07:56:04 +00:00
|
|
|
identifier, base];
|
2013-04-11 11:06:20 +00:00
|
|
|
[doc setHeader: @"In-Reply-To" value: rep parameters: nil];
|
|
|
|
ref = [rep mutableCopy];
|
2013-04-08 17:00:19 +00:00
|
|
|
#if 0
|
2013-04-11 11:06:20 +00:00
|
|
|
if (threadID > 1)
|
|
|
|
{
|
|
|
|
int index;
|
2013-04-08 15:50:32 +00:00
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
for (index = 1; index < threadID; index++)
|
2013-04-08 15:50:32 +00:00
|
|
|
{
|
2013-04-11 11:06:20 +00:00
|
|
|
[ref appendFormat: @"<alrm%@_%d@%@>",
|
2017-08-30 07:56:04 +00:00
|
|
|
identifier, index, base];
|
2013-04-08 15:50:32 +00:00
|
|
|
}
|
|
|
|
}
|
2013-04-11 11:06:20 +00:00
|
|
|
#endif
|
|
|
|
[doc setHeader: @"References" value: ref parameters: nil];
|
|
|
|
mID = [NSString stringWithFormat: @"<alrm%@_%d@%@>",
|
2017-08-30 07:56:04 +00:00
|
|
|
identifier, threadID, base];
|
2013-04-08 15:50:32 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mID = [NSString stringWithFormat: @"<alrm%@@%@>",
|
2017-08-30 07:56:04 +00:00
|
|
|
identifier, base];
|
2013-04-08 15:50:32 +00:00
|
|
|
}
|
2013-04-05 23:20:16 +00:00
|
|
|
|
2013-04-11 11:06:20 +00:00
|
|
|
if (YES == isClear && threadID <= 0)
|
2013-04-05 23:20:16 +00:00
|
|
|
{
|
2013-04-06 19:53:54 +00:00
|
|
|
if (YES == supersede)
|
|
|
|
{
|
|
|
|
/* Set all the headers likely to be used by clients to
|
|
|
|
* have this message supersede the original.
|
|
|
|
*/
|
|
|
|
[doc setHeader: @"Obsoletes" value: mID parameters: nil];
|
|
|
|
[doc setHeader: @"Replaces" value: mID parameters: nil];
|
|
|
|
[doc setHeader: @"Supersedes" value: mID parameters: nil];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Treat the clear as simply a repeat (new version) of the
|
|
|
|
* original message.
|
|
|
|
*/
|
|
|
|
[doc setHeader: @"Message-ID" value: mID parameters: nil];
|
|
|
|
}
|
2013-04-05 23:20:16 +00:00
|
|
|
}
|
2013-04-08 15:50:32 +00:00
|
|
|
else
|
2013-04-05 23:20:16 +00:00
|
|
|
{
|
|
|
|
[doc setHeader: @"Message-ID" value: mID parameters: nil];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((d = [e nextObject]) != nil)
|
|
|
|
{
|
2013-04-12 11:27:16 +00:00
|
|
|
if (YES == [d hasPrefix: @"{ResponsibleEmail}"])
|
2013-04-12 09:47:08 +00:00
|
|
|
{
|
2013-04-12 11:27:16 +00:00
|
|
|
NSString *s = [m objectForKey: @"ResponsibleEmail"];
|
|
|
|
|
|
|
|
if ([s length] > 0)
|
|
|
|
{
|
|
|
|
/* Use the ResponsibleEmail address from the alarm
|
|
|
|
*/
|
|
|
|
d = s;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Use the fallback (remaining text in the address)
|
|
|
|
*/
|
|
|
|
d = [d substringFromIndex: 18];
|
|
|
|
}
|
2013-04-12 09:47:08 +00:00
|
|
|
}
|
|
|
|
if (0 == [d length])
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2013-04-05 23:20:16 +00:00
|
|
|
NS_DURING
|
|
|
|
{
|
|
|
|
GSMimeDocument *msg;
|
|
|
|
|
|
|
|
msg = AUTORELEASE([doc copy]);
|
2013-04-08 15:50:32 +00:00
|
|
|
[msg setHeader: @"To" value: d parameters: nil];
|
2013-04-05 23:20:16 +00:00
|
|
|
[smtp send: msg];
|
|
|
|
}
|
|
|
|
NS_HANDLER
|
|
|
|
{
|
|
|
|
NSLog(@"Problem flushing email for address: %@, subject: %@, %@",
|
|
|
|
d, subject, localException);
|
|
|
|
}
|
|
|
|
NS_ENDHANDLER
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (email == nil)
|
|
|
|
{
|
|
|
|
email = [NSMutableDictionary new];
|
|
|
|
}
|
|
|
|
while ((d = [e nextObject]) != nil)
|
|
|
|
{
|
2014-05-14 21:52:58 +00:00
|
|
|
NSMutableDictionary *md;
|
2013-04-05 23:20:16 +00:00
|
|
|
NSString *msg;
|
|
|
|
|
2014-05-14 21:52:58 +00:00
|
|
|
if (YES == [d hasPrefix: @"{ResponsibleEmail}"])
|
|
|
|
{
|
|
|
|
NSString *s = [m objectForKey: @"ResponsibleEmail"];
|
|
|
|
|
|
|
|
if ([s length] > 0)
|
|
|
|
{
|
|
|
|
/* Use the ResponsibleEmail address from the alarm
|
|
|
|
*/
|
|
|
|
d = s;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Use the fallback (remaining text in the address)
|
|
|
|
*/
|
|
|
|
d = [d substringFromIndex: 18];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (0 == [d length])
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
md = [email objectForKey: d];
|
2013-04-05 23:20:16 +00:00
|
|
|
if (md == nil)
|
|
|
|
{
|
|
|
|
md = [NSMutableDictionary new];
|
|
|
|
[email setObject: md forKey: d];
|
|
|
|
RELEASE(md);
|
|
|
|
}
|
|
|
|
|
|
|
|
msg = [md objectForKey: subject];
|
|
|
|
|
|
|
|
/* If adding the new text would take an existing message over the
|
|
|
|
* size limit, send the existing stuff first.
|
|
|
|
*/
|
|
|
|
if ([msg length] > 0 && [msg length] + [text length] + 2 > 20*1024)
|
|
|
|
{
|
|
|
|
AUTORELEASE(RETAIN(msg));
|
|
|
|
[md removeObjectForKey: subject];
|
|
|
|
[self flushEmailForAddress: d
|
|
|
|
subject: subject
|
|
|
|
text: msg];
|
|
|
|
msg = nil;
|
|
|
|
}
|
|
|
|
if (msg == nil)
|
|
|
|
{
|
|
|
|
msg = text;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
msg = [msg stringByAppendingFormat: @"\n\n%@", text];
|
|
|
|
}
|
|
|
|
[md setObject: msg forKey: subject];
|
|
|
|
}
|
2012-02-19 11:59:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-05 13:50:10 +00:00
|
|
|
- (void) sms: (NSMutableDictionary*)m
|
|
|
|
identifier: (NSString*)identifier
|
|
|
|
isClear: (BOOL)isClear
|
|
|
|
to: (NSArray*)destinations
|
2012-02-19 11:59:22 +00:00
|
|
|
{
|
|
|
|
NSEnumerator *e = [destinations objectEnumerator];
|
|
|
|
NSString *d;
|
|
|
|
NSString *s;
|
|
|
|
NSString *t;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Perform {field-name} substitutions, but to shorten the message
|
|
|
|
* remove any Timestamp value from the dictionary.
|
|
|
|
*/
|
|
|
|
t = RETAIN([m objectForKey: @"Timestamp"]);
|
|
|
|
[m removeObjectForKey: @"Timestamp"];
|
2013-04-07 11:38:46 +00:00
|
|
|
s = replaceFields(m, [m objectForKey: @"Replacement"]);
|
2012-02-19 11:59:22 +00:00
|
|
|
if (t != nil)
|
|
|
|
{
|
|
|
|
[m setObject: t forKey: @"Timestamp"];
|
|
|
|
RELEASE(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sms == nil)
|
|
|
|
{
|
|
|
|
sms = [NSMutableDictionary new];
|
|
|
|
}
|
|
|
|
while ((d = [e nextObject]) != nil)
|
|
|
|
{
|
|
|
|
NSString *msg = [sms objectForKey: d];
|
|
|
|
|
|
|
|
if (msg == nil)
|
|
|
|
{
|
|
|
|
msg = s;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int missed = 0;
|
|
|
|
|
|
|
|
if ([msg hasPrefix: @"Missed("] == YES)
|
|
|
|
{
|
|
|
|
NSRange r = [msg rangeOfString: @")"];
|
|
|
|
|
|
|
|
r = NSMakeRange(7, r.location - 7);
|
|
|
|
msg = [msg substringWithRange: r];
|
|
|
|
missed = [msg intValue];
|
|
|
|
}
|
|
|
|
missed++;
|
|
|
|
msg = [NSString stringWithFormat: @"Missed(%d)\n%@", missed, s];
|
|
|
|
}
|
|
|
|
[sms setObject: msg forKey: d];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) timeout: (NSTimer*)t
|
|
|
|
{
|
|
|
|
[self flushSms];
|
|
|
|
[self flushEmail];
|
|
|
|
}
|
|
|
|
@end
|
|
|
|
|