(feat) first pass at support for recurring events/tasks email alarms (fixes #1053)
parent
8cadf5cbbd
commit
78045b14be
3
NEWS
3
NEWS
|
@ -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
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"];
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -898,6 +898,7 @@ convention:
|
|||
|
||||
- (NSMutableDictionary *) quickRecordFromContent: (NSString *) theContent
|
||||
container: (id) theContainer
|
||||
nameInContainer: (NSString *) nameInContainer
|
||||
{
|
||||
NSMutableDictionary *fields;
|
||||
CardElement *element;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue