From 2f66264657a51269fbff21ad0b858b92d2ef9a23 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 20 Aug 2010 01:38:33 +0000 Subject: [PATCH] Monotone-Parent: dedf484aec95d33480d529af12e81cb45edb7dd0 Monotone-Revision: ce0a852faf4ba22891a76c3c85731b7a32e2d14a Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2010-08-20T01:38:33 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 3 + .../Appointments/SOGoEMailAlarmsManager.h | 53 +++ .../Appointments/SOGoEMailAlarmsManager.m | 321 ++++++++++++++++++ 3 files changed, 377 insertions(+) create mode 100644 SoObjects/Appointments/SOGoEMailAlarmsManager.h create mode 100644 SoObjects/Appointments/SOGoEMailAlarmsManager.m diff --git a/ChangeLog b/ChangeLog index 885747a24..f7a3f9e0a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,9 @@ 2010-08-19 Wolfgang Sourdeau + * SoObjects/Appointments/SOGoEMailAlarmsManager.[hm]: new GCS + aware singleton class for main email alarms operations on the db. + * SoObjects/Mailer/SOGoMailFolder.m (-deleteUIDs:inContext:): make the use of the "result" variable clearer by declaring it with a proper class name and avoiding type confusion within the code. diff --git a/SoObjects/Appointments/SOGoEMailAlarmsManager.h b/SoObjects/Appointments/SOGoEMailAlarmsManager.h new file mode 100644 index 000000000..ca3df303e --- /dev/null +++ b/SoObjects/Appointments/SOGoEMailAlarmsManager.h @@ -0,0 +1,53 @@ +/* SOGoEMailAlarmsManager.h - this file is part of SOGo + * + * Copyright (C) 2010 Inverse inc. + * + * Author: Wolfgang Sourdeau + * + * 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 + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef SOGOEMAILALARMSMANAGER_H +#define SOGOEMAILALARMSMANAGER_H + +#import + +@class NSCalendarDate; + +@class iCalCalendar; + +@class SOGoCalendarComponent; + +@interface SOGoEMailAlarmsManager : NSObject + ++ (id) sharedEMailAlarmsManager; + +/* PUT */ +- (void) handleAlarmsInCalendar: (iCalCalendar *) calendar + fromComponent: (SOGoCalendarComponent *) component; + +/* DELETE */ +- (void) deleteAlarmsFromComponent: (SOGoCalendarComponent *) component; + +/* fetch and cleanup */ +- (NSArray *) scheduledAlarmsFromDate: (NSCalendarDate *) fromDate + toDate: (NSCalendarDate *) toDate + withOwners: (NSMutableArray **) owners; +- (void) deleteAlarmsUntilDate: (NSCalendarDate *) untilDate; + +@end + +#endif /* SOGOEMAILALARMSMANAGER_H */ diff --git a/SoObjects/Appointments/SOGoEMailAlarmsManager.m b/SoObjects/Appointments/SOGoEMailAlarmsManager.m new file mode 100644 index 000000000..33d6eb6d5 --- /dev/null +++ b/SoObjects/Appointments/SOGoEMailAlarmsManager.m @@ -0,0 +1,321 @@ +/* SOGoEMailAlarmsManager.m - this file is part of SOGo + * + * Copyright (C) 2010 Inverse inc. + * + * Author: Wolfgang Sourdeau + * + * 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 + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#import +#import +#import +#import +#import + +#import + +#import +#import +#import +#import +#import + +#import +#import +#import + +#import "SOGoAppointmentFolder.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 +{ + static id sharedEMailAlarmsManager = nil; + + if (!sharedEMailAlarmsManager) + sharedEMailAlarmsManager = [self new]; + + 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]; +} + +- (void) deleteAlarmsFromComponent: (SOGoCalendarComponent *) component +{ + GCSAlarmsFolder *af; + NSString *path; + + af = [[GCSFolderManager defaultFolderManager] alarmsFolder]; + path = [[component container] ocsPath]; + [af deleteRecordForEntryWithCName: [component nameInContainer] + inCalendarAtPath: path]; +} + +- (iCalCalendar *) _lookupCalendarMatchingRecord: (NSDictionary *) record +{ + iCalCalendar *calendar; + GCSFolder *folder; + NSDictionary *eventRecord; + + folder = [[GCSFolderManager defaultFolderManager] + folderAtPath: [record objectForKey: @"c_path"]]; + eventRecord = [folder + recordOfEntryWithName: [record objectForKey: @"c_name"]]; + calendar = [iCalCalendar parseSingleFromSource: + [eventRecord objectForKey: @"c_content"]]; + + return calendar; +} + +- (iCalEntityObject *) _lookupEntityMatchingRecord: (NSDictionary *) record + inCalendar: (iCalCalendar *) calendar +{ + NSArray *entities; + iCalEntityObject *entity, *testEntity; + int count, max, testRecId; + + entities = [calendar events]; + max = [entities count]; + if (max == 0) + { + entities = [calendar todos]; + max = [entities count]; + } + + if (max > 0) + { + entity = nil; + for (count = 0; !entity && count < max; count++) + { + testEntity = [entities objectAtIndex: count]; + testRecId = (int) [[testEntity recurrenceId] timeIntervalSince1970]; + if ([[record objectForKey: @"c_recurrence_id"] intValue] == testRecId) + entity = testEntity; + } + } + else + [self errorWithFormat: + @"(inconsistency) no handled entity found for record: %@", + record]; + + return entity; +} + +- (void) _extractOwner: (NSString **) owner + fromPath: (NSString *) path +{ + NSArray *parts; + + parts = [path componentsSeparatedByString: @"/"]; + if ([parts count] > 2) + *owner = [parts objectAtIndex: 2]; +} + +- (iCalAlarm *) _lookupAlarmMatchingRecord: (NSDictionary *) record + withOwner: (NSString **) owner +{ + iCalCalendar *calendar; + iCalEntityObject *entity; + iCalAlarm *alarm; + NSArray *alarms; + int alarmNbr; + + calendar = [self _lookupCalendarMatchingRecord: record]; + entity = [self _lookupEntityMatchingRecord: record inCalendar: calendar]; + alarmNbr = [[record objectForKey: @"c_alarm_number"] intValue]; + alarms = [entity alarms]; + if (alarmNbr < [alarms count]) + { + alarm = [alarms objectAtIndex: alarmNbr]; + [self _extractOwner: owner + fromPath: [record objectForKey: @"c_path"]]; + } + else + { + [self errorWithFormat: @"alarm number mismatch for record: %@", record]; + alarm = nil; + } + + return alarm; +} + +- (NSArray *) scheduledAlarmsFromDate: (NSCalendarDate *) fromDate + toDate: (NSCalendarDate *) toDate + withOwners: (NSMutableArray **) owners +{ + GCSAlarmsFolder *af; + iCalAlarm *alarm; + NSMutableArray *alarms; + NSDictionary *record; + NSArray *records; + int count, max; + NSString *owner; + + af = [[GCSFolderManager defaultFolderManager] alarmsFolder]; + 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]; + if (alarm) + { + [alarms addObject: alarm]; + if (owners) + [*owners addObject: owner]; + } + } + + return alarms; +} + +- (void) deleteAlarmsUntilDate: (NSCalendarDate *) untilDate +{ + GCSAlarmsFolder *af; + + af = [[GCSFolderManager defaultFolderManager] alarmsFolder]; + + [af deleteRecordsForEntriesUntilDate: untilDate]; +} + +@end