(feat) first pass at support for recurring events/tasks email alarms (fixes #1053)

pull/225/head
Ludovic Marcotte 2016-11-02 18:16:45 -04:00
parent 8cadf5cbbd
commit 78045b14be
17 changed files with 210 additions and 245 deletions

3
NEWS
View File

@ -1,6 +1,9 @@
3.2.2 (2016-11-DD)
------------------
New features
- [core] support repetitive email alarms on tasks and events (#1053)
Bug fixes
- [web] fixed mail settings persistence when sorting by arrival date

View File

@ -1,8 +1,6 @@
/* GCSAlarmsFolder.h - this file is part of $PROJECT_NAME_HERE$
*
* Copyright (C) 2010 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2010-2016 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -60,8 +58,6 @@
- (void) deleteRecordForEntryWithCName: (NSString *) cname
inCalendarAtPath: (NSString *) path;
- (void) deleteRecordsForEntriesUntilDate: (NSCalendarDate *) date;
@end
#endif /* GCSALARMSFOLDER_H */

View File

@ -1,6 +1,6 @@
/* GCSAlarmsFolder.m - this file is part of SOGo
*
* Copyright (C) 2010-2014 Inverse inc.
* Copyright (C) 2010-2016 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -409,36 +409,4 @@ static NSString *alarmsFolderURLString = nil;
}
}
- (void) deleteRecordsForEntriesUntilDate: (NSCalendarDate *) date
{
EOAdaptorChannel *tc;
EOAdaptorContext *context;
EOEntity *entity;
EOSQLQualifier *qualifier;
NSException *error;
tc = [self _acquireStoreChannel];
if (tc)
{
context = [tc adaptorContext];
entity = [self _storeTableEntityForChannel: tc];
qualifier = [[EOSQLQualifier alloc] initWithEntity: entity
qualifierFormat:
@"c_alarm_date <= %d",
(int) [date timeIntervalSince1970]];
[qualifier autorelease];
[context beginTransaction];
error = [tc deleteRowsDescribedByQualifierX: qualifier];
if (error)
{
[context rollbackTransaction];
[self errorWithFormat:@"%s: cannot delete record: %@",
__PRETTY_FUNCTION__, error];
}
else
[context commitTransaction];
[self _releaseChannel: tc];
}
}
@end

View File

@ -1017,7 +1017,21 @@ andAttribute: (EOAttribute *)_attribute
|| *_baseVersion == [storedVersion unsignedIntValue])
{
/* extract quick info */
quickRow = [theComponent performSelector: @selector(quickRecordFromContent:container:) withObject: _content withObject: theContainer];
NSMethodSignature *aSignature;
NSInvocation *anInvocation;
SEL aSelector;
aSelector = @selector(quickRecordFromContent:container:nameInContainer:);
aSignature = [[theComponent class] instanceMethodSignatureForSelector: aSelector];
anInvocation = [NSInvocation invocationWithMethodSignature:aSignature];
[anInvocation setSelector: aSelector];
[anInvocation setTarget: theComponent];
[anInvocation setArgument:&_content atIndex: 2];
[anInvocation setArgument:&theContainer atIndex: 3];
[anInvocation setArgument:&_name atIndex: 4];
[anInvocation invoke];
[anInvocation getReturnValue: &quickRow];
if (quickRow)
{
[quickRow setObject:_name forKey:@"c_name"];

View File

@ -954,7 +954,7 @@ static Class iCalEventK = nil;
// alarm defined.
if ([[component alarms] count])
{
alarm = [component firstDisplayOrAudioAlarm];
alarm = [component firstSupportedAlarm];
[row setObject: [NSNumber numberWithInt: [[alarm nextAlarmDate] timeIntervalSince1970]]
forKey: @"c_nextalarm"];
}
@ -1030,7 +1030,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
(endDate && [dateRange containsDate: endDate]))
{
// We must pass nil to :container here in order to avoid re-entrancy issues.
newRecord = [self _fixupRecord: [component quickRecordFromContent: nil container: nil]];
newRecord = [self _fixupRecord: [component quickRecordFromContent: nil container: nil nameInContainer: nil]];
[ma replaceObjectAtIndex: recordIndex withObject: newRecord];
}
else
@ -1047,7 +1047,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
// The recurrence id of the exception is outside the date range;
// simply add the exception to the records array.
// We must pass nil to :container here in order to avoid re-entrancy issues.
newRecord = [self _fixupRecord: [component quickRecordFromContent: nil container: nil]];
newRecord = [self _fixupRecord: [component quickRecordFromContent: nil container: nil nameInContainer: nil]];
if ([newRecord objectForKey: @"startDate"] && [newRecord objectForKey: @"endDate"]) {
newRecordRange = [NGCalendarDateRange
calendarDateRangeWithStartDate: [newRecord objectForKey: @"startDate"]

View File

@ -683,15 +683,6 @@
newUid = [newUid substringToIndex: [newUid length]-4];
[newObject setUid: newUid];
}
if ([[SOGoSystemDefaults sharedSystemDefaults] enableEMailAlarms])
{
SOGoEMailAlarmsManager *eaMgr;
eaMgr = [SOGoEMailAlarmsManager sharedEMailAlarmsManager];
[eaMgr handleAlarmsInCalendar: [newObject parent]
fromComponent: self];
}
}
- (NSException *) saveCalendar: (iCalCalendar *) newCalendar
@ -1459,23 +1450,6 @@
return nil;
}
- (id) PUTAction: (WOContext *) localContext
{
if ([[SOGoSystemDefaults sharedSystemDefaults] enableEMailAlarms])
{
SOGoEMailAlarmsManager *eaMgr;
iCalCalendar *putCalendar;
WORequest *rq;
rq = [localContext request];
putCalendar = [iCalCalendar parseSingleFromSource: [rq contentAsString]];
eaMgr = [SOGoEMailAlarmsManager sharedEMailAlarmsManager];
[eaMgr handleAlarmsInCalendar: putCalendar
fromComponent: self];
}
return [super PUTAction: localContext];
}
// /* Overriding this method dramatically speeds up PROPFIND request, but may
// otherwise be a bad idea... Wait and see. */

View File

@ -1,6 +1,6 @@
/* SOGoEMailAlarmsManager.h - this file is part of SOGo
*
* Copyright (C) 2010-2014 Inverse inc.
* Copyright (C) 2010-2016 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -42,8 +42,7 @@
/* fetch and cleanup */
- (NSArray *) scheduledAlarmsFromDate: (NSCalendarDate *) fromDate
toDate: (NSCalendarDate *) toDate
withOwners: (NSMutableArray **) owners;
- (void) deleteAlarmsUntilDate: (NSCalendarDate *) untilDate;
withMetadata: (NSMutableArray *) metadata;
@end

View File

@ -1,6 +1,6 @@
/* SOGoEMailAlarmsManager.m - this file is part of SOGo
*
* Copyright (C) 2010-2014 Inverse inc.
* Copyright (C) 2010-2016 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -35,87 +35,11 @@
#import <GDLContentStore/GCSFolderManager.h>
#import "SOGoAppointmentFolder.h"
#import "SOGoAppointmentFolders.h"
#import "SOGoCalendarComponent.h"
#import "SOGoEMailAlarmsManager.h"
@interface iCalEntityObject (SOGoAlarmsExtension)
- (void) findSoonerEMailAlarmAfterDate: (NSCalendarDate *) refDate
inAlarm: (iCalAlarm **) alarm;
@end
@interface iCalCalendar (SOGoAlarmsExtension)
- (void) findSoonerEMailAlarmAfterDate: (NSCalendarDate *) refDate
inAlarm: (iCalAlarm **) alarm;
@end
@implementation iCalEntityObject (SOGoAlarmsExtension)
- (void) findSoonerEMailAlarmAfterDate: (NSCalendarDate *) refDate
inAlarm: (iCalAlarm **) alarm
{
int count, max;
NSArray *alarms;
iCalAlarm *currentAlarm;
NSString *action;
NSCalendarDate *soonerDate, *testDate;
soonerDate = [*alarm nextAlarmDate];
alarms = [self alarms];
max = [alarms count];
for (count = 0; count < max; count++)
{
currentAlarm = [alarms objectAtIndex: count];
action = [[currentAlarm action] uppercaseString];
if ([action isEqualToString: @"EMAIL"])
{
testDate = [currentAlarm nextAlarmDate];
if (testDate
&& [refDate earlierDate: testDate] == refDate
&& (!soonerDate
|| [soonerDate earlierDate: testDate] == testDate))
{
*alarm = currentAlarm;
soonerDate = testDate;
}
}
}
}
@end
@implementation iCalCalendar (SOGoAlarmsExtension)
- (void) findSoonerEMailAlarmAfterDate: (NSCalendarDate *) refDate
inAlarm: (iCalAlarm **) alarm
{
int count, max;
iCalEntityObject *child;
BOOL done;
/* Here we only search for email alarms in the first event. This
should be fixed sometime. */
done = NO;
max = [children count];
for (count = 0; !done && count < max; count++)
{
child = [children objectAtIndex: count];
if ([child isKindOfClass: [iCalEvent class]]
|| [child isKindOfClass: [iCalToDo class]])
{
[child findSoonerEMailAlarmAfterDate: refDate inAlarm: alarm];
done = YES;
}
}
}
@end
@implementation SOGoEMailAlarmsManager
+ (id) sharedEMailAlarmsManager
@ -128,50 +52,11 @@
return sharedEMailAlarmsManager;
}
- (void) _writeAlarmCoordinates: (iCalAlarm *) alarm
fromComponent: (SOGoCalendarComponent *) component
{
GCSAlarmsFolder *af;
NSString *path, *cname;
iCalEntityObject *entity;
int alarmNbr;
af = [[GCSFolderManager defaultFolderManager] alarmsFolder];
path = [[component container] ocsPath];
cname = [component nameInContainer];
if (alarm)
{
entity = [alarm parent];
alarmNbr = [[entity alarms] indexOfObject: alarm];
[af writeRecordForEntryWithCName: cname
inCalendarAtPath: path
forUID: [entity uid]
recurrenceId: [entity recurrenceId]
alarmNumber: [NSNumber numberWithInt: alarmNbr]
andAlarmDate: [alarm nextAlarmDate]];
}
else
[af deleteRecordForEntryWithCName: cname
inCalendarAtPath: path];
}
- (void) handleAlarmsInCalendar: (iCalCalendar *) calendar
fromComponent: (SOGoCalendarComponent *) component
{
iCalAlarm *alarm;
NSCalendarDate *now;
now = [NSCalendarDate calendarDate];
alarm = nil;
[calendar findSoonerEMailAlarmAfterDate: now
inAlarm: &alarm];
[self _writeAlarmCoordinates: alarm
fromComponent: component];
}
//
// This method is called SOGoCalendarCompoent: -prepareDelete when
// a component is being deleted. We of course remove all associated
// when an event or task is being deleted.
//
- (void) deleteAlarmsFromComponent: (SOGoCalendarComponent *) component
{
GCSAlarmsFolder *af;
@ -246,19 +131,52 @@
*owner = [parts objectAtIndex: 2];
}
- (void) _extractContainer: (NSString **) container
fromPath: (NSString *) path
{
NSArray *parts;
parts = [path componentsSeparatedByString: @"/"];
if ([parts count] > 4)
*container = [parts objectAtIndex: 4];
}
- (SOGoAppointmentFolder *) _lookupContainerMatchingRecord: (NSDictionary *) record
{
SOGoAppointmentFolders *folders;
NSString *container, *owner;
SOGoUserFolder *userFolder;
SOGoUser *user;
WOContext *context;
[self _extractOwner: &owner fromPath: [record objectForKey: @"c_path"]];
[self _extractContainer: &container fromPath: [record objectForKey: @"c_path"]];
user = [SOGoUser userWithLogin: owner];
userFolder = [SOGoUserFolder objectWithName: owner inContainer: nil];
context = [WOContext context];
[context setActiveUser: user];
folders = [userFolder lookupName: @"Calendar"
inContext: context
acquire: NO];
return [folders lookupName: container
inContext: context
acquire: NO];
}
- (iCalAlarm *) _lookupAlarmMatchingRecord: (NSDictionary *) record
withOwner: (NSString **) owner
withEntity: (iCalEntityObject **) entity
{
iCalCalendar *calendar;
iCalEntityObject *entity;
iCalAlarm *alarm;
NSArray *alarms;
int alarmNbr;
calendar = [self _lookupCalendarMatchingRecord: record];
entity = [self _lookupEntityMatchingRecord: record inCalendar: calendar];
*entity = [self _lookupEntityMatchingRecord: record inCalendar: calendar];
alarmNbr = [[record objectForKey: @"c_alarm_number"] intValue];
alarms = [entity alarms];
alarms = [*entity alarms];
if (alarmNbr < [alarms count])
{
alarm = [alarms objectAtIndex: alarmNbr];
@ -276,8 +194,10 @@
- (NSArray *) scheduledAlarmsFromDate: (NSCalendarDate *) fromDate
toDate: (NSCalendarDate *) toDate
withOwners: (NSMutableArray **) owners
withMetadata: (NSMutableArray *) metadata
{
SOGoAppointmentFolder *container;
iCalEntityObject *entity;
GCSAlarmsFolder *af;
iCalAlarm *alarm;
NSMutableArray *alarms;
@ -290,31 +210,25 @@
records = [af recordsForEntriesFromDate: fromDate toDate: toDate];
max = [records count];
alarms = [NSMutableArray arrayWithCapacity: max];
if (owners)
*owners = [NSMutableArray arrayWithCapacity: max];
for (count = 0; count < max; count++)
{
record = [records objectAtIndex: count];
alarm = [self _lookupAlarmMatchingRecord: record
withOwner: &owner];
withOwner: &owner
withEntity: &entity];
if (alarm)
{
container = [self _lookupContainerMatchingRecord: record];
[alarms addObject: alarm];
if (owners)
[*owners addObject: owner];
[metadata addObject: [NSDictionary dictionaryWithObjectsAndKeys: owner, @"owner",
record, @"record",
container, @"container",
entity, @"entity",
nil]];
}
}
return alarms;
}
- (void) deleteAlarmsUntilDate: (NSCalendarDate *) untilDate
{
GCSAlarmsFolder *af;
af = [[GCSFolderManager defaultFolderManager] alarmsFolder];
[af deleteRecordsForEntriesUntilDate: untilDate];
}
@end

View File

@ -80,7 +80,8 @@
}
- (NSMutableDictionary *) quickRecordFromContent: (NSString *) theContent
container: (id) theContainer
container: (id) theContainer
nameInContainer: (NSString *) nameInContainer
{
CardGroup *element;
NSArray *elements;
@ -97,7 +98,7 @@
element = nil;
}
return [(id)element quickRecordFromContent: theContent container: theContainer];
return [(id)element quickRecordFromContent: theContent container: theContainer nameInContainer: nameInContainer];
}
@end

View File

@ -1,6 +1,6 @@
/* iCalEntityObject+SOGo.h - this file is part of SOGo
*
* Copyright (C) 2007-2015 Inverse inc.
* Copyright (C) 2007-2016 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -65,13 +65,15 @@ extern NSNumber *iCalDistantFutureNumber;
forAllDay: (BOOL) allDay;
- (NSMutableDictionary *) quickRecordFromContent: (NSString *) theContent
container: (id) theContainer;
container: (id) theContainer
nameInContainer: (NSString *) nameInContainer;
- (iCalAlarm *) firstSupportedAlarm;
- (iCalAlarm *) firstDisplayOrAudioAlarm;
- (void) updateNextAlarmDateInRow: (NSMutableDictionary *) row
forContainer: (id) theContainer;
forContainer: (id) theContainer
nameInContainer: (NSString *) nameInContainer;
@end

View File

@ -1,6 +1,6 @@
/* iCalEntityObject+SOGo.m - this file is part of SOGo
*
* Copyright (C) 2007-2015 Inverse inc.
* Copyright (C) 2007-2016 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -23,6 +23,9 @@
#import <Foundation/NSValue.h>
#import <Foundation/NSTimeZone.h>
#import <GDLContentStore/GCSAlarmsFolder.h>
#import <GDLContentStore/GCSFolderManager.h>
#import <NGCards/iCalTrigger.h>
#import <NGCards/iCalRepeatableEntityObject.h>
#import <NGCards/NSString+NGCards.h>
@ -37,6 +40,7 @@
#import <SOGo/NSArray+Utilities.h>
#import <SOGo/SOGoSource.h>
#import <SOGo/SOGoSystemDefaults.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserDefaults.h>
#import <SOGo/SOGoUserManager.h>
@ -554,6 +558,7 @@ NSNumber *iCalDistantFutureNumber = nil;
- (NSMutableDictionary *) quickRecordFromContent: (NSString *) theContent
container: (id) theContainer
nameInContainer: (NSString *) nameInContainer
{
[self subclassResponsibility: _cmd];
@ -612,7 +617,6 @@ NSNumber *iCalDistantFutureNumber = nil;
}
return createdByData;
;
}
//
@ -659,10 +663,45 @@ NSNumber *iCalDistantFutureNumber = nil;
return nil;
}
- (iCalAlarm *) firstEmailAlarm
{
iCalAlarm *anAlarm;
NSArray *alarms;
int i;
alarms = [self alarms];
for (i = 0; i < [alarms count]; i++)
{
anAlarm = [[self alarms] objectAtIndex: i];
if ([[anAlarm action] caseInsensitiveCompare: @"EMAIL"] == NSOrderedSame)
return anAlarm;
}
return nil;
}
- (void) updateNextAlarmDateInRow: (NSMutableDictionary *) row
forContainer: (id) theContainer
nameInContainer: (NSString *) nameInContainer
{
NSCalendarDate *nextAlarmDate;
GCSAlarmsFolder *af;
NSString *path;
if ([[SOGoSystemDefaults sharedSystemDefaults] enableEMailAlarms])
{
af = [[GCSFolderManager defaultFolderManager] alarmsFolder];
path = [theContainer ocsPath];
}
else
{
af = nil;
path = nil;
}
nextAlarmDate = nil;
@ -680,7 +719,7 @@ NSNumber *iCalDistantFutureNumber = nil;
if (![(id)self isRecurrent])
{
anAlarm = [self firstDisplayOrAudioAlarm];
if (anAlarm)
if ((anAlarm = [self firstDisplayOrAudioAlarm]))
{
webstatus = [[anAlarm trigger] value: 0 ofAttribute: @"x-webstatus"];
if (!webstatus
@ -688,10 +727,27 @@ NSNumber *iCalDistantFutureNumber = nil;
!= NSOrderedSame))
nextAlarmDate = [anAlarm nextAlarmDate];
}
else
{
// TODO: handle email alarms here
}
else if ((anAlarm = [self firstEmailAlarm]) && af)
{
nextAlarmDate = [anAlarm nextAlarmDate];
// The email alarm is too old, let's just remove it
if ([nextAlarmDate earlierDate: [NSDate date]] == nextAlarmDate)
nextAlarmDate = nil;
else
{
int alarmNbr;
alarmNbr = [[self alarms] indexOfObject: anAlarm];
[af writeRecordForEntryWithCName: nameInContainer
inCalendarAtPath: path
forUID: [self uid]
recurrenceId: nil
alarmNumber: [NSNumber numberWithInt: alarmNbr]
andAlarmDate: nextAlarmDate];
}
}
}
// Recurring event/task
else
@ -765,22 +821,30 @@ NSNumber *iCalDistantFutureNumber = nil;
if ([[o alarms] count])
{
anAlarm = [self firstDisplayOrAudioAlarm];
if (anAlarm)
if ((anAlarm = [self firstDisplayOrAudioAlarm]))
{
webstatus = [[anAlarm trigger] value: 0 ofAttribute: @"x-webstatus"];
if (!webstatus
|| ([webstatus caseInsensitiveCompare: @"TRIGGERED"]
!= NSOrderedSame))
v = delta;
nextAlarmDate = [NSDate dateWithTimeIntervalSince1970: [[[alarms objectAtIndex: i] objectForKey: @"c_nextalarm"] intValue]];
}
else
{
// TODO: handle email alarms here
}
}
else if ((anAlarm = [self firstEmailAlarm]) && af)
{
int alarmNbr;
nextAlarmDate = [NSDate dateWithTimeIntervalSince1970: [[[alarms objectAtIndex: i] objectForKey: @"c_nextalarm"] intValue]];
alarmNbr = [[self alarms] indexOfObject: anAlarm];
[af writeRecordForEntryWithCName: nameInContainer
inCalendarAtPath: path
forUID: [self uid]
recurrenceId: [self recurrenceId]
alarmNumber: [NSNumber numberWithInt: alarmNbr]
andAlarmDate: nextAlarmDate];
}
}
}
} // for ( ... )
} // if (theContainer)
@ -791,7 +855,14 @@ NSNumber *iCalDistantFutureNumber = nil;
[row setObject: [NSNumber numberWithInt: [nextAlarmDate timeIntervalSince1970]]
forKey: @"c_nextalarm"];
else
[row setObject: [NSNumber numberWithInt: 0] forKey: @"c_nextalarm"];
{
[row setObject: [NSNumber numberWithInt: 0] forKey: @"c_nextalarm"];
// Delete old email alarms
if (af)
[af deleteRecordForEntryWithCName: nameInContainer
inCalendarAtPath: [theContainer ocsPath]];
}
}
@end

View File

@ -68,6 +68,7 @@
//
- (NSMutableDictionary *) quickRecordFromContent: (NSString *) theContent
container: (id) theContainer
nameInContainer: (NSString *) nameInContainer
{
NSMutableDictionary *row;
NSCalendarDate *startDate, *endDate;
@ -240,7 +241,7 @@
[partstates release];
/* handle alarms */
[self updateNextAlarmDateInRow: row forContainer: theContainer];
[self updateNextAlarmDateInRow: row forContainer: theContainer nameInContainer: nameInContainer];
/* handle categories */
categories = [self categories];

View File

@ -220,6 +220,7 @@
- (NSMutableDictionary *) quickRecordFromContent: (NSString *) theContent
container: (id) theContainer
nameInContainer: (NSString *) nameInContainer
{
NSMutableDictionary *row;
NSCalendarDate *startDate, *dueDate, *completed;
@ -350,7 +351,7 @@
[partstates release];
/* handle alarms */
[self updateNextAlarmDateInRow: row forContainer: theContainer];
[self updateNextAlarmDateInRow: row forContainer: theContainer nameInContainer: nameInContainer];
categories = [self categories];
if ([categories count] > 0)

View File

@ -898,6 +898,7 @@ convention:
- (NSMutableDictionary *) quickRecordFromContent: (NSString *) theContent
container: (id) theContainer
nameInContainer: (NSString *) nameInContainer
{
NSMutableDictionary *fields;
CardElement *element;

View File

@ -1,6 +1,6 @@
/* NGVCard+SOGo.m - this file is part of SOGo
*
* Copyright (C) 2009-2014 Inverse inc.
* Copyright (C) 2009-2016 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -69,6 +69,8 @@
- (NSMutableDictionary *) quickRecordFromContent: (NSString *) theContent
container: (id) theContainer
nameInContainer: (NSString *) nameInContainer
{
NSMutableDictionary *fields;
NSString *value;

View File

@ -1,6 +1,6 @@
/* SOGoEAlarmsNotifier.m - this file is part of SOGo
*
* Copyright (C) 2011-2014 Inverse inc.
* Copyright (C) 2011-2016 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -31,12 +31,13 @@
#import <NGCards/iCalAlarm.h>
#import "SOGo/SOGoCredentialsFile.h"
#import <SOGo/NSCalendarDate+SOGo.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/SOGoCredentialsFile.h>
#import <SOGo/SOGoMailer.h>
#import <SOGo/SOGoProductLoader.h>
#import <SOGo/SOGoUser.h>
#import <Appointments/iCalEntityObject+SOGo.h>
#import <Appointments/iCalPerson+SOGo.h>
#import <Appointments/SOGoEMailAlarmsManager.h>
@ -179,12 +180,15 @@
- (BOOL) run
{
SOGoEMailAlarmsManager *eaMgr;
SOGoCredentialsFile *cf;
NSCalendarDate *startDate, *toDate;
NSArray *alarms;
NSMutableArray *owners;
SOGoEMailAlarmsManager *eaMgr;
NSMutableArray *metadata;
iCalEntityObject *entity;
SOGoCredentialsFile *cf;
NSString *credsFilename;
NSDictionary *d;
NSArray *alarms;
int count, max;
if ([[NSUserDefaults standardUserDefaults] stringForKey: @"h"])
@ -211,6 +215,7 @@
eaMgr = [NSClassFromString (@"SOGoEMailAlarmsManager")
sharedEMailAlarmsManager];
metadata = [[NSMutableArray alloc] init];
startDate = [NSCalendarDate calendarDate];
toDate = [startDate addYear: 0 month: 0 day: 0
hour: 0 minute: 0
@ -219,13 +224,26 @@
hour: 0 minute: -5
second: 0]
toDate: toDate
withOwners: &owners];
withMetadata: metadata];
max = [alarms count];
for (count = 0; count < max; count++)
[self _processAlarm: [alarms objectAtIndex: count]
withOwner: [owners objectAtIndex: count]];
withOwner: [[metadata objectAtIndex: count] objectForKey: @"owner"]];
// We now update the next alarm date (if any, for recurring
// events or tasks for example). This will also delete any emai
// alarms that are no longer relevant
max = [metadata count];
for (count = 0; count < max; count++)
{
d = [metadata objectAtIndex: count];
entity = [d objectForKey: @"entity"];
[entity quickRecordFromContent: nil
container: [d objectForKey: @"container"]
nameInContainer: [[d objectForKey: @"record"] objectForKey: @"c_name"]];
}
[eaMgr deleteAlarmsUntilDate: toDate];
return YES;
}

View File

@ -552,7 +552,7 @@ static NSArray *reminderValues = nil;
alarmData = nil;
if ([component hasAlarms])
{
anAlarm = [component firstSupportedAlarm];
anAlarm = [component firstDisplayOrAudioAlarm];
trigger = [anAlarm trigger];
if (![[trigger valueType] length] || [[trigger valueType] caseInsensitiveCompare: @"DURATION"] == NSOrderedSame)
{