diff --git a/ChangeLog b/ChangeLog index 83ecce731..facd2f85d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,44 @@ +2010-08-19 Wolfgang Sourdeau + + * UI/WebServerResources/UIxReminderEditor.js + (initialiseFormValues): added code to configure the "actionList" + if present (email alarms enabled). + (onEditorOkClick): modify the parent's reminderAction, + reminderEmailOrganizer, reminderEmailAttendees when email alarms + are available. "reminderAction" is conditionally set to "display" + otherwise. + + * UI/Scheduler/UIxReminderEditor.m (-emailAlarmsEnabled): new accessor. + + * SoObjects/Appointments/SOGoCalendarComponent.m + (-saveComponent:): invoke SOGoEMailAlarmsManager to register any + email alarms in the saved component. + (-PUTAction:): new super method to perform the same as the above. + (-prepareDelete): new super method. Invoke SOGoEMailAlarmsManager + to unregister any email alarms in the deleted component. + + * UI/Scheduler/UIxComponentEditor.m (-init): added the + "reminderAction", "reminderEmailOrganizer" and + "reminderEmailAttendees" ivars. + (_loadEMailAlarm:) new setup method for setting up parameters that + are specific to email alarms. + (_appendAttendees:toEmailAlarm:,_appendOrganizerToEmailAlarm:): + new method for adding "attendees" to email alarms. + (-emailAlarmsEnabled): new accessor. + + * SoObjects/Appointments/SOGoAppointmentObject.m (-prepareDelete): + we now invoke -[super prepareDelete] since SOGoCalendarComponent + now implements the method. + (-DELETEAction:): invoke -prepareDelete instead of + -prepareDeleteOccurence: since we want -[super prepareDelete] to + be invoked from here too. + + * Main/SOGo.m (-_checkMandatoryTables): added code to create the + alarms table if email alarms are enabled. + + * SoObjects/SOGo/SOGoSystemDefaults.m (-enableEMailAlarms): new + method for the "SOGoEnableEMailAlarms" user default. + 2010-08-19 Francis Lachapelle * UI/WebServerResources/generic.js (showPromptDialog): new diff --git a/Main/SOGo.m b/Main/SOGo.m index 78b884745..180920515 100644 --- a/Main/SOGo.m +++ b/Main/SOGo.m @@ -30,6 +30,8 @@ #import #import +#import +#import #import #import @@ -201,6 +203,7 @@ static BOOL debugLeaks; - (BOOL) _checkMandatoryTables { GCSChannelManager *cm; + GCSFolderManager *fm; NSString *urlStrings[] = {@"SOGoProfileURL", @"OCSFolderInfoURL", nil}; NSString **urlString; NSString *value; @@ -227,6 +230,12 @@ static BOOL debugLeaks; } } + if (ok && [defaults enableEMailAlarms]) + { + fm = [GCSFolderManager defaultFolderManager]; + [[fm alarmsFolder] createFolderIfNotExists]; + } + return ok; } diff --git a/SOPE/GDLContentStore/ChangeLog b/SOPE/GDLContentStore/ChangeLog index 75341dc1c..3fc7b7117 100644 --- a/SOPE/GDLContentStore/ChangeLog +++ b/SOPE/GDLContentStore/ChangeLog @@ -1,3 +1,18 @@ +2010-08-19 Wolfgang Sourdeau + + * GCSSpecialQueries.m (-createEMailAlarmsFolderWithName:): new sql + helper methods + (emailAlarmsAttributeTypes:): new helper method that returns the + types pertaining to the adaptor. + + * GCSFolderManager.m (-alarmsFolder): new helper method. + + * GCSAlarmsFolder.[hm]: new class module for handling alarm + references. + + * GCSFolder.m (-_channelManager): made method private. + (-folderManager): removed method. + 2010-06-11 Wolfgang Sourdeau * GCSFolderManager.m diff --git a/SOPE/GDLContentStore/GCSFolder.h b/SOPE/GDLContentStore/GCSFolder.h index 670059c37..b1370b6e2 100644 --- a/SOPE/GDLContentStore/GCSFolder.h +++ b/SOPE/GDLContentStore/GCSFolder.h @@ -94,9 +94,6 @@ - (NSURL *) aclLocation; - (NSString *) folderTypeName; -- (GCSFolderManager *) folderManager; -- (GCSChannelManager *) channelManager; - - (NSString *) storeTableName; - (NSString *) quickTableName; - (NSString *) aclTableName; diff --git a/SOPE/GDLContentStore/GCSFolder.m b/SOPE/GDLContentStore/GCSFolder.m index 2f856d418..4b26a124a 100644 --- a/SOPE/GDLContentStore/GCSFolder.m +++ b/SOPE/GDLContentStore/GCSFolder.m @@ -192,11 +192,8 @@ static NSArray *contentFieldNames = nil; return folderTypeName; } -- (GCSFolderManager *)folderManager { - return folderManager; -} -- (GCSChannelManager *)channelManager { - return [[self folderManager] channelManager]; +- (GCSChannelManager *)_channelManager { + return [folderManager channelManager]; } - (NSString *)storeTableName { @@ -216,28 +213,28 @@ static NSArray *contentFieldNames = nil; /* channels */ - (EOAdaptorChannel *)acquireStoreChannel { - return [[self channelManager] acquireOpenChannelForURL:[self location]]; + return [[self _channelManager] acquireOpenChannelForURL:[self location]]; } - (EOAdaptorChannel *)acquireQuickChannel { - return [[self channelManager] acquireOpenChannelForURL:[self quickLocation]]; + return [[self _channelManager] acquireOpenChannelForURL:[self quickLocation]]; } - (EOAdaptorChannel *)acquireAclChannel { - return [[self channelManager] acquireOpenChannelForURL:[self aclLocation]]; + return [[self _channelManager] acquireOpenChannelForURL:[self aclLocation]]; } - (void)releaseChannel:(EOAdaptorChannel *)_channel { - [[self channelManager] releaseChannel:_channel]; + [[self _channelManager] releaseChannel:_channel]; if (debugOn) [self debugWithFormat:@"released channel: %@", _channel]; } - (BOOL)canConnectStore { - return [[self channelManager] canConnect:[self location]]; + return [[self _channelManager] canConnect:[self location]]; } - (BOOL)canConnectQuick { - return [[self channelManager] canConnect:[self quickLocation]]; + return [[self _channelManager] canConnect:[self quickLocation]]; } - (BOOL)canConnectAcl { - return [[self channelManager] canConnect:[self quickLocation]]; + return [[self _channelManager] canConnect:[self quickLocation]]; } /* errors */ @@ -278,12 +275,12 @@ static NSArray *contentFieldNames = nil; /* operations */ - (NSArray *)subFolderNames { - return [[self folderManager] listSubFoldersAtPath:[self path] - recursive:NO]; + return [folderManager listSubFoldersAtPath:[self path] + recursive:NO]; } - (NSArray *)allSubFolderNames { - return [[self folderManager] listSubFoldersAtPath:[self path] - recursive:YES]; + return [folderManager listSubFoldersAtPath:[self path] + recursive:YES]; } - (GCSTableRequirement) _tableRequirementForFields: (NSArray *) fields @@ -515,7 +512,6 @@ static NSArray *contentFieldNames = nil; { [self errorWithFormat:@"%s: cannot execute quick-fetch SQL '%@': %@", __PRETTY_FUNCTION__, sql, error]; - [self releaseChannel: channel]; results = nil; } else @@ -529,8 +525,8 @@ static NSArray *contentFieldNames = nil; /* release channels */ - [self releaseChannel: channel]; } + [self releaseChannel: channel]; // NSLog(@"/running query"); } else diff --git a/SOPE/GDLContentStore/GCSFolderManager.h b/SOPE/GDLContentStore/GCSFolderManager.h index 27aa09acc..6e395b5f0 100644 --- a/SOPE/GDLContentStore/GCSFolderManager.h +++ b/SOPE/GDLContentStore/GCSFolderManager.h @@ -32,7 +32,7 @@ */ @class NSString, NSArray, NSURL, NSDictionary, NSException; -@class GCSChannelManager, GCSFolder, GCSFolderType; +@class GCSChannelManager, GCSAlarmsFolder, GCSFolder, GCSFolderType; @interface GCSFolderManager : NSObject { @@ -70,6 +70,9 @@ - (NSException *)createFolderOfType:(NSString *)_type withName:(NSString *)_name atPath:(NSString *)_path; - (NSException *)deleteFolderAtPath:(NSString *)_path; +/* alarms */ +- (GCSAlarmsFolder *)alarmsFolder; + /* folder types */ - (GCSFolderType *)folderTypeWithName:(NSString *)_name; diff --git a/SOPE/GDLContentStore/GCSFolderManager.m b/SOPE/GDLContentStore/GCSFolderManager.m index 34e3f2ca5..45ccce026 100644 --- a/SOPE/GDLContentStore/GCSFolderManager.m +++ b/SOPE/GDLContentStore/GCSFolderManager.m @@ -37,13 +37,15 @@ #import #import -#import "GCSFolderManager.h" #import "GCSChannelManager.h" -#import "GCSFolderType.h" +#import "EOAdaptorChannel+GCS.h" +#import "GCSAlarmsFolder.h" #import "GCSFolder.h" +#import "GCSFolderType.h" #import "GCSSpecialQueries.h" #import "NSURL+GCS.h" -#import "EOAdaptorChannel+GCS.h" + +#import "GCSFolderManager.h" /* Required database schema: @@ -323,6 +325,11 @@ static NSCharacterSet *asciiAlphaNumericCS = nil; return [folder autorelease]; } +- (GCSAlarmsFolder *) alarmsFolder +{ + return [GCSAlarmsFolder alarmsFolderWithFolderManager: self]; +} + /* path SQL */ - (NSString *)generateSQLWhereForInternalNames:(NSArray *)_names diff --git a/SOPE/GDLContentStore/GCSSpecialQueries.h b/SOPE/GDLContentStore/GCSSpecialQueries.h index 48674e02b..af406a844 100644 --- a/SOPE/GDLContentStore/GCSSpecialQueries.h +++ b/SOPE/GDLContentStore/GCSSpecialQueries.h @@ -31,6 +31,9 @@ @interface GCSSpecialQueries : NSObject +- (NSString *) createEMailAlarmsFolderWithName: (NSString *) tableName; +- (NSDictionary *) emailAlarmsAttributeTypes; + - (NSString *) createFolderTableWithName: (NSString *) tableName; - (NSString *) createFolderACLTableWithName: (NSString *) tableName; diff --git a/SOPE/GDLContentStore/GCSSpecialQueries.m b/SOPE/GDLContentStore/GCSSpecialQueries.m index 24092ebc2..4effe6602 100644 --- a/SOPE/GDLContentStore/GCSSpecialQueries.m +++ b/SOPE/GDLContentStore/GCSSpecialQueries.m @@ -77,6 +77,20 @@ @implementation GCSSpecialQueries +- (NSString *) createEMailAlarmsFolderWithName: (NSString *) tableName +{ + [self subclassResponsibility: _cmd]; + + return nil; +} + +- (NSDictionary *) emailAlarmsAttributeTypes +{ + [self subclassResponsibility: _cmd]; + + return nil; +} + - (NSString *) createFolderTableWithName: (NSString *) tableName { [self subclassResponsibility: _cmd]; @@ -95,6 +109,38 @@ @implementation GCSPostgreSQLSpecialQueries +- (NSString *) createEMailAlarmsFolderWithName: (NSString *) tableName +{ + static NSString *sqlFolderFormat + = (@"CREATE TABLE %@ (" + @" c_path VARCHAR(255) NOT NULL," + @" c_name VARCHAR(255) NOT NULL," + @" c_uid VARCHAR(255) NOT NULL," + @" c_recurrence_id INT NULL," + @" c_alarm_number INT NOT NULL," + @" c_alarm_date INT NOT NULL)"); + + return [NSString stringWithFormat: sqlFolderFormat, tableName]; +} + +- (NSDictionary *) emailAlarmsAttributeTypes +{ + static NSMutableDictionary *types = nil; + + if (!types) + { + types = [NSMutableDictionary new]; + [types setObject: @"varchar" forKey: @"c_path"]; + [types setObject: @"varchar" forKey: @"c_name"]; + [types setObject: @"varchar" forKey: @"c_uid"]; + [types setObject: @"int" forKey: @"c_recurrence_id"]; + [types setObject: @"int" forKey: @"c_alarm_number"]; + [types setObject: @"int" forKey: @"c_alarm_date"]; + } + + return types; +} + - (NSString *) createFolderTableWithName: (NSString *) tableName { static NSString *sqlFolderFormat @@ -126,6 +172,38 @@ @implementation GCSMySQLSpecialQueries +- (NSString *) createEMailAlarmsFolderWithName: (NSString *) tableName +{ + static NSString *sqlFolderFormat + = (@"CREATE TABLE %@ (" + @" c_path VARCHAR(255) NOT NULL," + @" c_name VARCHAR(255) NOT NULL," + @" c_uid VARCHAR(255) NOT NULL," + @" c_recurrence_id INT NULL," + @" c_alarm_number INT NOT NULL," + @" c_alarm_date INT NOT NULL)"); + + return [NSString stringWithFormat: sqlFolderFormat, tableName]; +} + +- (NSDictionary *) emailAlarmsAttributeTypes +{ + static NSMutableDictionary *types = nil; + + if (!types) + { + types = [NSMutableDictionary new]; + [types setObject: @"varchar" forKey: @"c_path"]; + [types setObject: @"varchar" forKey: @"c_name"]; + [types setObject: @"varchar" forKey: @"c_uid"]; + [types setObject: @"int" forKey: @"c_recurrence_id"]; + [types setObject: @"int" forKey: @"c_alarm_number"]; + [types setObject: @"int" forKey: @"c_alarm_date"]; + } + + return types; +} + - (NSString *) createFolderTableWithName: (NSString *) tableName { static NSString *sqlFolderFormat @@ -157,6 +235,38 @@ @implementation GCSOracleSpecialQueries +- (NSString *) createEMailAlarmsFolderWithName: (NSString *) tableName +{ + static NSString *sqlFolderFormat + = (@"CREATE TABLE %@ (" + @" c_path VARCHAR2(255) NOT NULL," + @" c_name VARCHAR2(255) NOT NULL," + @" c_uid VARCHAR2(255) NOT NULL," + @" c_recurrence_id INTEGER NULL," + @" c_alarm_number INTEGER NOT NULL," + @" c_alarm_date INTEGER NOT NULL)"); + + return [NSString stringWithFormat: sqlFolderFormat, tableName]; +} + +- (NSDictionary *) emailAlarmsAttributeTypes +{ + static NSMutableDictionary *types = nil; + + if (!types) + { + types = [NSMutableDictionary new]; + [types setObject: @"varchar2" forKey: @"c_path"]; + [types setObject: @"varchar2" forKey: @"c_name"]; + [types setObject: @"varchar2" forKey: @"c_uid"]; + [types setObject: @"integer" forKey: @"c_recurrence_id"]; + [types setObject: @"integer" forKey: @"c_alarm_number"]; + [types setObject: @"integer" forKey: @"c_alarm_date"]; + } + + return types; +} + - (NSString *) createFolderTableWithName: (NSString *) tableName { static NSString *sqlFolderFormat diff --git a/SOPE/GDLContentStore/GNUmakefile b/SOPE/GDLContentStore/GNUmakefile index 7963a46d2..bb50fc57b 100644 --- a/SOPE/GDLContentStore/GNUmakefile +++ b/SOPE/GDLContentStore/GNUmakefile @@ -24,6 +24,7 @@ libGDLContentStore_HEADER_FILES += \ NSURL+GCS.h \ EOAdaptorChannel+GCS.h \ \ + GCSAlarmsFolder.h \ GCSContext.h \ GCSFieldInfo.h \ GCSFolder.h \ @@ -39,6 +40,7 @@ libGDLContentStore_OBJC_FILES += \ EOAdaptorChannel+GCS.m \ EOQualifier+GCS.m \ \ + GCSAlarmsFolder.m \ GCSContext.m \ GCSFieldInfo.m \ GCSFolder.m \ diff --git a/SOPE/NGCards/ChangeLog b/SOPE/NGCards/ChangeLog index 1a22c37c3..64682c35a 100644 --- a/SOPE/NGCards/ChangeLog +++ b/SOPE/NGCards/ChangeLog @@ -1,3 +1,8 @@ +2010-08-19 Wolfgang Sourdeau + + * iCalAlarm.m (-setComment, -setSummary, -setAction) + (-setAttendees): new accessors. + 2010-08-13 Wolfgang Sourdeau * iCalAlarm.m (-nextAlarmDate): new utility method split from the diff --git a/SOPE/NGCards/iCalAlarm.h b/SOPE/NGCards/iCalAlarm.h index ecb39f5c6..ed8d698f2 100644 --- a/SOPE/NGCards/iCalAlarm.h +++ b/SOPE/NGCards/iCalAlarm.h @@ -41,6 +41,15 @@ - (void) setRecurrenceRule: (NSString *) _recurrenceRule; - (NSString *) recurrenceRule; +- (void) setSummary: (NSString *) summary; +- (NSString *) summary; +- (void) setComment: (NSString *) comment; +- (NSString *) comment; + +- (void) setAttendees: (NSArray *) attendees; +- (NSArray *) attendees; +- (void) removeAllAttendees; + - (NSCalendarDate *) nextAlarmDate; @end diff --git a/SOPE/NGCards/iCalAlarm.m b/SOPE/NGCards/iCalAlarm.m index d07d81f4e..2eab33947 100644 --- a/SOPE/NGCards/iCalAlarm.m +++ b/SOPE/NGCards/iCalAlarm.m @@ -19,6 +19,7 @@ 02111-1307, USA. */ +#import #import #import #import @@ -44,8 +45,12 @@ tagClass = [iCalAttachment class]; else if ([classTag isEqualToString: @"RRULE"]) tagClass = [iCalRecurrenceRule class]; + else if ([classTag isEqualToString: @"ATTENDEE"]) + tagClass = [iCalPerson class]; else if ([classTag isEqualToString: @"ACTION"] - || [classTag isEqualToString: @"COMMENT"]) + || [classTag isEqualToString: @"COMMENT"] + || [classTag isEqualToString: @"DESCRIPTION"] + || [classTag isEqualToString: @"SUMMARY"]) tagClass = [CardElement class]; else tagClass = [super classForTag: classTag]; @@ -75,21 +80,10 @@ return (iCalAttachment *) [self uniqueChildWithTag: @"attach"]; } -- (void) setComment: (NSString *) _value -{ - [[self uniqueChildWithTag: @"comment"] setValue: 0 - to: _value]; -} - -- (NSString *) comment -{ - return [[self uniqueChildWithTag: @"comment"] value: 0]; -} - - (void) setAction: (NSString *) _value { [[self uniqueChildWithTag: @"action"] setValue: 0 - to: _value]; + to: _value]; } - (NSString *) action @@ -97,12 +91,50 @@ return [[self uniqueChildWithTag: @"action"] value: 0]; } +- (void) setSummary: (NSString *) _value +{ + [[self uniqueChildWithTag: @"summary"] setValue: 0 + to: _value]; +} + +- (NSString *) summary +{ + return [[self uniqueChildWithTag: @"summary"] value: 0]; +} + +- (void) setComment: (NSString *) _value +{ + [[self uniqueChildWithTag: @"description"] setValue: 0 + to: _value]; +} + +- (NSString *) comment +{ + return [[self uniqueChildWithTag: @"description"] value: 0]; +} + - (void) setRecurrenceRule: (NSString *) _recurrenceRule { [[self uniqueChildWithTag: @"rrule"] setValue: 0 to: _recurrenceRule]; } +- (void) setAttendees: (NSArray *) attendees +{ + [self removeAllAttendees]; + [self addChildren: attendees]; +} + +- (NSArray *) attendees +{ + return [self childrenWithTag: @"attendee"]; +} + +- (void) removeAllAttendees +{ + [children removeObjectsInArray: [self attendees]]; +} + - (NSString *) recurrenceRule { return [[self uniqueChildWithTag: @"rrule"] value: 0]; @@ -110,7 +142,6 @@ - (NSCalendarDate *) nextAlarmDate { - Class parentClass; iCalTrigger *aTrigger; NSCalendarDate *relationDate, *nextAlarmDate; NSString *relation; @@ -121,19 +152,19 @@ nextAlarmDate = nil; - parentClass = [parent class]; - if ([parentClass isKindOfClass: [iCalEvent class]] - || [parentClass isKindOfClass: [iCalToDo class]]) + if ([parent isKindOfClass: [iCalEvent class]] + || [parent isKindOfClass: [iCalToDo class]]) { aTrigger = [self trigger]; - if ([[aTrigger valueType] caseInsensitiveCompare: @"DURATION"]) + if ([[aTrigger valueType] caseInsensitiveCompare: @"DURATION"] + == NSOrderedSame) { relation = [aTrigger relationType]; anInterval = [[aTrigger value] durationAsTimeInterval]; if ([relation caseInsensitiveCompare: @"END"] == NSOrderedSame) { - if ([parentClass isKindOfClass: [iCalEvent class]]) + if ([parent isKindOfClass: [iCalEvent class]]) relationDate = [(iCalEvent *) parent endDate]; else relationDate = [(iCalToDo *) parent due]; @@ -148,7 +179,7 @@ } else [self warnWithFormat: @"alarms not handled for elements of class '%@'", - NSStringFromClass (parentClass)]; + NSStringFromClass ([parent class])]; return nextAlarmDate; } diff --git a/SoObjects/Appointments/GNUmakefile b/SoObjects/Appointments/GNUmakefile index d31fe2de0..e1f1b2c77 100644 --- a/SoObjects/Appointments/GNUmakefile +++ b/SoObjects/Appointments/GNUmakefile @@ -42,6 +42,8 @@ Appointments_OBJC_FILES = \ SOGoAptMailICalReply.m \ SOGoAptMailUpdate.m \ SOGoAptMailReceipt.m \ + \ + SOGoEMailAlarmsManager.m Appointments_RESOURCE_FILES += \ Version \ diff --git a/SoObjects/Appointments/SOGoAppointmentObject.m b/SoObjects/Appointments/SOGoAppointmentObject.m index 7e687bcab..47f549ec4 100644 --- a/SoObjects/Appointments/SOGoAppointmentObject.m +++ b/SoObjects/Appointments/SOGoAppointmentObject.m @@ -608,7 +608,7 @@ // participation state has changed. // - uid is the actual UID of the user for whom we must // update the calendar event (with the participation change) -// - delegate is the delegated attendee if any +// - delegate is the delegate attendee if any // // This method is called multiple times, in order to update the // status of the attendee in calendars for the particular event UID. @@ -668,7 +668,7 @@ else otherDelegate = NO; - /* we handle the addition/deletion of delegated users */ + /* we handle the addition/deletion of delegate users */ addDelegate = NO; removeDelegate = NO; if (delegate) @@ -696,7 +696,7 @@ { [event removeFromAttendees: otherDelegate]; - // Verify if the delegate was already delegated + // Verify if the delegate was already delegate delegateEmail = [otherDelegate delegatedTo]; if ([delegateEmail length]) delegateEmail = [delegateEmail rfc822Email]; @@ -777,31 +777,31 @@ if ([delegateEmail length]) otherDelegate = [event findAttendeeWithEmail: delegateEmail]; else - otherDelegate = NO; + otherDelegate = nil; - /* We handle the addition/deletion of delegated users */ + /* We handle the addition/deletion of delegate users */ addDelegate = NO; removeDelegate = NO; if (delegate) { if (otherDelegate) { - // There was already a delegated + // There was already a delegate if (![delegate hasSameEmailAddress: otherDelegate]) { - // The delegated has changed + // The delegate has changed removeDelegate = YES; addDelegate = YES; } } else - // There was no previous delegated + // There was no previous delegate addDelegate = YES; } else { if (otherDelegate) - // The user has removed the delegated + // The user has removed the delegate removeDelegate = YES; } @@ -846,7 +846,7 @@ delegatedUID = [otherDelegate uid]; if (delegatedUID) - // Delegated attendee is a local user; remove event from his calendar + // Delegate attendee is a local user; remove event from his calendar [self _removeEventFromUID: delegatedUID owner: [theOwnerUser login] withRecurrenceId: [event recurrenceId]]; @@ -880,7 +880,7 @@ [event addToAttendees: delegate]; if (delegatedUID) - // Delegated attendee is a local user; add event to his calendar + // Delegate attendee is a local user; add event to his calendar [self _addOrUpdateEvent: event forUID: delegatedUID owner: [theOwnerUser login]]; @@ -1217,7 +1217,7 @@ { [self prepareDeleteOccurence: nil]; - return nil; + return [super prepareDelete]; } /* message type */ @@ -1260,6 +1260,7 @@ return partStats; } +#warning parseSingleFromSource is invoked far too many times: maybe we should use an additional ivar to store the new iCalendar - (void) _setupResponseCalendarInRequest: (WORequest *) rq { iCalCalendar *calendar, *putCalendar; @@ -1412,7 +1413,7 @@ // - (id) DELETEAction: (WOContext *) _ctx { - [self prepareDeleteOccurence: nil]; + [self prepareDelete]; return [super DELETEAction: _ctx]; } @@ -1428,10 +1429,10 @@ NSArray *roles; WORequest *rq; id response; - + rq = [_ctx request]; roles = [[context activeUser] rolesForObject: self inContext: context]; - + // // We check if we gave only the "Respond To" right and someone is actually // responding to one of our invitation. In this case, _setupResponseCalendarInRequest @@ -1469,6 +1470,7 @@ BOOL scheduling; calendar = [iCalCalendar parseSingleFromSource: [rq contentAsString]]; + event = [[calendar events] objectAtIndex: 0]; ownerUser = [SOGoUser userWithLogin: owner]; scheduling = [self _shouldScheduleEvent: [event organizer]]; diff --git a/SoObjects/Appointments/SOGoCalendarComponent.m b/SoObjects/Appointments/SOGoCalendarComponent.m index 6a5a9d4fa..0c4f2aaf9 100644 --- a/SoObjects/Appointments/SOGoCalendarComponent.m +++ b/SoObjects/Appointments/SOGoCalendarComponent.m @@ -60,6 +60,7 @@ #import "SOGoAptMailICalReply.h" #import "SOGoAptMailNotification.h" #import "SOGoAptMailReceipt.h" +#import "SOGoEMailAlarmsManager.h" #import "iCalEntityObject+SOGo.h" #import "iCalPerson+SOGo.h" #import "iCalRepeatableEntityObject+SOGo.h" @@ -590,6 +591,7 @@ static inline BOOL _occurenceHasID (iCalRepeatableEntityObject *occurence, - (void) saveComponent: (iCalRepeatableEntityObject *) newObject { NSString *newiCalString, *newUid; + SOGoEMailAlarmsManager *eaMgr; if (!isNew && [newObject isRecurrent]) @@ -611,6 +613,10 @@ static inline BOOL _occurenceHasID (iCalRepeatableEntityObject *occurence, [newObject setUid: newUid]; } + eaMgr = [SOGoEMailAlarmsManager sharedEMailAlarmsManager]; + [eaMgr handleAlarmsInCalendar: [newObject parent] + fromComponent: self]; + newiCalString = [[newObject parent] versitString]; [self saveContentString: newiCalString]; @@ -1157,6 +1163,32 @@ static inline BOOL _occurenceHasID (iCalRepeatableEntityObject *occurence, return [self component: YES secure: NO]; } +#warning alarms: we don not handle occurrences +- (NSException *) prepareDelete +{ + SOGoEMailAlarmsManager *eaMgr; + + eaMgr = [SOGoEMailAlarmsManager sharedEMailAlarmsManager]; + [eaMgr deleteAlarmsFromComponent: self]; + + return nil; +} + +- (id) PUTAction: (WOContext *) localContext +{ + SOGoEMailAlarmsManager *eaMgr; + WORequest *rq; + iCalCalendar *putCalendar; + + 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. */ // - (NSDictionary*) valuesForKeys: (NSArray*)keys diff --git a/SoObjects/SOGo/SOGoSystemDefaults.h b/SoObjects/SOGo/SOGoSystemDefaults.h index cd8e3a834..a543cdfba 100644 --- a/SoObjects/SOGo/SOGoSystemDefaults.h +++ b/SoObjects/SOGo/SOGoSystemDefaults.h @@ -42,6 +42,8 @@ - (BOOL) isCalendarDAVAccessEnabled; - (BOOL) isAddressBookDAVAccessEnabled; +- (BOOL) enableEMailAlarms; + - (NSString *) faviconRelativeURL; - (NSString *) zipPath; - (int) port; diff --git a/SoObjects/SOGo/SOGoSystemDefaults.m b/SoObjects/SOGo/SOGoSystemDefaults.m index 659aff14f..8b20b5838 100644 --- a/SoObjects/SOGo/SOGoSystemDefaults.m +++ b/SoObjects/SOGo/SOGoSystemDefaults.m @@ -221,6 +221,11 @@ BootstrapNSUserDefaults () return [self boolForKey: @"SOGoAddressBookDAVAccessEnabled"]; } +- (BOOL) enableEMailAlarms +{ + return [self boolForKey: @"SOGoEnableEMailAlarms"]; +} + - (NSString *) faviconRelativeURL { return [self stringForKey: @"SOGoFaviconRelativeURL"]; diff --git a/Tools/GNUmakefile b/Tools/GNUmakefile index df613bff5..8ac1e8c29 100644 --- a/Tools/GNUmakefile +++ b/Tools/GNUmakefile @@ -25,7 +25,14 @@ $(SOGO_SLAPD_SOCKD)_OBJC_FILES += \ SOGoSockDScanner.m \ SOGoSockDOperation.m \ -TOOL_NAME = $(SOGO_TOOL) $(SOGO_SLAPD_SOCKD) +SOGO_EALARMS_NOTIFY = sogo-ealarms-notify +$(SOGO_EALARMS_NOTIFY)_INSTALL_DIR = $(SOGO_ADMIN_TOOLS) +$(SOGO_EALARMS_NOTIFY)_OBJC_FILES += \ + sogo-ealarms-notify.m \ + \ + SOGoEAlarmsNotifier.m + +TOOL_NAME = $(SOGO_TOOL) $(SOGO_SLAPD_SOCKD) $(SOGO_EALARMS_NOTIFY) -include GNUmakefile.preamble include $(GNUSTEP_MAKEFILES)/tool.make diff --git a/UI/Scheduler/BrazilianPortuguese.lproj/Localizable.strings b/UI/Scheduler/BrazilianPortuguese.lproj/Localizable.strings index 1056a595e..ffd5c47eb 100644 --- a/UI/Scheduler/BrazilianPortuguese.lproj/Localizable.strings +++ b/UI/Scheduler/BrazilianPortuguese.lproj/Localizable.strings @@ -406,6 +406,12 @@ "reminder_END" = "fim do evento"; "Reminder Details" = "Reminder Details"; +"Choose a Reminder Action" = "Choose a Reminder Action"; +"Show an Alert" = "Show an Alert"; +"Send an E-mail" = "Send an E-mail"; +"Email Organizer" = "Email Organizer"; +"Email Attendees" = "Email Attendees"; + "zoom_400" = "400%"; "zoom_200" = "200%"; "zoom_100" = "100%"; diff --git a/UI/Scheduler/Czech.lproj/Localizable.strings b/UI/Scheduler/Czech.lproj/Localizable.strings index 783ad46e0..f1d3aa459 100644 --- a/UI/Scheduler/Czech.lproj/Localizable.strings +++ b/UI/Scheduler/Czech.lproj/Localizable.strings @@ -406,6 +406,12 @@ "reminder_END" = "konci události"; "Reminder Details" = "Podrobnosti připomenutí"; +"Choose a Reminder Action" = "Choose a Reminder Action"; +"Show an Alert" = "Show an Alert"; +"Send an E-mail" = "Send an E-mail"; +"Email Organizer" = "Email Organizer"; +"Email Attendees" = "Email Attendees"; + "zoom_400" = "400%"; "zoom_200" = "200%"; "zoom_100" = "100%"; diff --git a/UI/Scheduler/Dutch.lproj/Localizable.strings b/UI/Scheduler/Dutch.lproj/Localizable.strings index 4c90b1aec..90bc1772f 100644 --- a/UI/Scheduler/Dutch.lproj/Localizable.strings +++ b/UI/Scheduler/Dutch.lproj/Localizable.strings @@ -406,6 +406,12 @@ "reminder_END" = "the event ends"; "Reminder Details" = "Reminder Details"; +"Choose a Reminder Action" = "Choose a Reminder Action"; +"Show an Alert" = "Show an Alert"; +"Send an E-mail" = "Send an E-mail"; +"Email Organizer" = "Email Organizer"; +"Email Attendees" = "Email Attendees"; + "zoom_400" = "400%"; "zoom_200" = "200%"; "zoom_100" = "100%"; diff --git a/UI/Scheduler/English.lproj/Localizable.strings b/UI/Scheduler/English.lproj/Localizable.strings index 859f69fec..bc9d3c875 100644 --- a/UI/Scheduler/English.lproj/Localizable.strings +++ b/UI/Scheduler/English.lproj/Localizable.strings @@ -406,6 +406,12 @@ "reminder_END" = "the event ends"; "Reminder Details" = "Reminder Details"; +"Choose a Reminder Action" = "Choose a Reminder Action"; +"Show an Alert" = "Show an Alert"; +"Send an E-mail" = "Send an E-mail"; +"Email Organizer" = "Email Organizer"; +"Email Attendees" = "Email Attendees"; + "zoom_400" = "400%"; "zoom_200" = "200%"; "zoom_100" = "100%"; diff --git a/UI/Scheduler/French.lproj/Localizable.strings b/UI/Scheduler/French.lproj/Localizable.strings index 1b461afb4..a8fc90d22 100644 --- a/UI/Scheduler/French.lproj/Localizable.strings +++ b/UI/Scheduler/French.lproj/Localizable.strings @@ -402,10 +402,16 @@ "reminder_DAYS" = "jours"; "reminder_BEFORE" = "avant"; "reminder_AFTER" = "après"; -"reminder_START" = "l'événement débute"; -"reminder_END" = "l'événement se termine"; +"reminder_START" = "le début de 'événement"; +"reminder_END" = "la fin de l'événement"; "Reminder Details" = "Détails du rappel"; +"Choose a Reminder Action" = "Choisir une action pour le rappel"; +"Show an Alert" = "Afficher une alerte"; +"Send an E-mail" = "Envoyer un courrier"; +"Email Organizer" = "À l'organisateur"; +"Email Attendees" = "Aux invités"; + "zoom_400" = "400%"; "zoom_200" = "200%"; "zoom_100" = "100%"; diff --git a/UI/Scheduler/German.lproj/Localizable.strings b/UI/Scheduler/German.lproj/Localizable.strings index dc6e18e5f..eda1cdbbf 100644 --- a/UI/Scheduler/German.lproj/Localizable.strings +++ b/UI/Scheduler/German.lproj/Localizable.strings @@ -406,6 +406,12 @@ "reminder_END" = "der Termin endet"; "Reminder Details" = "Erinnerungsdetails"; +"Choose a Reminder Action" = "Choose a Reminder Action"; +"Show an Alert" = "Show an Alert"; +"Send an E-mail" = "Send an E-mail"; +"Email Organizer" = "Email Organizer"; +"Email Attendees" = "Email Attendees"; + "zoom_400" = "400%"; "zoom_200" = "200%"; "zoom_100" = "100%"; diff --git a/UI/Scheduler/Hungarian.lproj/Localizable.strings b/UI/Scheduler/Hungarian.lproj/Localizable.strings index c48189748..081fb6318 100644 --- a/UI/Scheduler/Hungarian.lproj/Localizable.strings +++ b/UI/Scheduler/Hungarian.lproj/Localizable.strings @@ -406,6 +406,12 @@ "reminder_END" = "az esemény végződik"; "Reminder Details" = "Reminder Details"; +"Choose a Reminder Action" = "Choose a Reminder Action"; +"Show an Alert" = "Show an Alert"; +"Send an E-mail" = "Send an E-mail"; +"Email Organizer" = "Email Organizer"; +"Email Attendees" = "Email Attendees"; + "zoom_400" = "400%"; "zoom_200" = "200%"; "zoom_100" = "100%"; diff --git a/UI/Scheduler/Italian.lproj/Localizable.strings b/UI/Scheduler/Italian.lproj/Localizable.strings index 7584ba278..e7aac9d88 100644 --- a/UI/Scheduler/Italian.lproj/Localizable.strings +++ b/UI/Scheduler/Italian.lproj/Localizable.strings @@ -406,6 +406,12 @@ "reminder_END" = "the event ends"; "Reminder Details" = "Reminder Details"; +"Choose a Reminder Action" = "Choose a Reminder Action"; +"Show an Alert" = "Show an Alert"; +"Send an E-mail" = "Send an E-mail"; +"Email Organizer" = "Email Organizer"; +"Email Attendees" = "Email Attendees"; + "zoom_400" = "400%"; "zoom_200" = "200%"; "zoom_100" = "100%"; diff --git a/UI/Scheduler/Polish.lproj/Localizable.strings b/UI/Scheduler/Polish.lproj/Localizable.strings index c7925bf1d..8cd95872c 100644 --- a/UI/Scheduler/Polish.lproj/Localizable.strings +++ b/UI/Scheduler/Polish.lproj/Localizable.strings @@ -406,6 +406,12 @@ "reminder_END" = "końcem wydarzenia"; "Reminder Details" = "Szczegóły przypomnienia"; +"Choose a Reminder Action" = "Choose a Reminder Action"; +"Show an Alert" = "Show an Alert"; +"Send an E-mail" = "Send an E-mail"; +"Email Organizer" = "Email Organizer"; +"Email Attendees" = "Email Attendees"; + "zoom_400" = "400%"; "zoom_200" = "200%"; "zoom_100" = "100%"; diff --git a/UI/Scheduler/Russian.lproj/Localizable.strings b/UI/Scheduler/Russian.lproj/Localizable.strings index 150cc50e4..c90ce6e6a 100644 --- a/UI/Scheduler/Russian.lproj/Localizable.strings +++ b/UI/Scheduler/Russian.lproj/Localizable.strings @@ -406,6 +406,12 @@ "reminder_END" = "конца события"; "Reminder Details" = "Reminder Details"; +"Choose a Reminder Action" = "Choose a Reminder Action"; +"Show an Alert" = "Show an Alert"; +"Send an E-mail" = "Send an E-mail"; +"Email Organizer" = "Email Organizer"; +"Email Attendees" = "Email Attendees"; + "zoom_400" = "400%"; "zoom_200" = "200%"; "zoom_100" = "100%"; diff --git a/UI/Scheduler/Spanish.lproj/Localizable.strings b/UI/Scheduler/Spanish.lproj/Localizable.strings index cf8df618d..b5d094681 100644 --- a/UI/Scheduler/Spanish.lproj/Localizable.strings +++ b/UI/Scheduler/Spanish.lproj/Localizable.strings @@ -406,6 +406,12 @@ "reminder_END" = "the event ends"; "Reminder Details" = "Reminder Details"; +"Choose a Reminder Action" = "Choose a Reminder Action"; +"Show an Alert" = "Show an Alert"; +"Send an E-mail" = "Send an E-mail"; +"Email Organizer" = "Email Organizer"; +"Email Attendees" = "Email Attendees"; + "zoom_400" = "400%"; "zoom_200" = "200%"; "zoom_100" = "100%"; diff --git a/UI/Scheduler/Swedish.lproj/Localizable.strings b/UI/Scheduler/Swedish.lproj/Localizable.strings index 24f721339..67f218f30 100644 --- a/UI/Scheduler/Swedish.lproj/Localizable.strings +++ b/UI/Scheduler/Swedish.lproj/Localizable.strings @@ -406,6 +406,12 @@ "reminder_END" = "händelserna slutar"; "Reminder Details" = "Påminnelsedetaljer"; +"Choose a Reminder Action" = "Choose a Reminder Action"; +"Show an Alert" = "Show an Alert"; +"Send an E-mail" = "Send an E-mail"; +"Email Organizer" = "Email Organizer"; +"Email Attendees" = "Email Attendees"; + "zoom_400" = "400%"; "zoom_200" = "200%"; "zoom_100" = "100%"; diff --git a/UI/Scheduler/UIxComponentEditor.h b/UI/Scheduler/UIxComponentEditor.h index 692a19112..e9378320d 100644 --- a/UI/Scheduler/UIxComponentEditor.h +++ b/UI/Scheduler/UIxComponentEditor.h @@ -72,6 +72,9 @@ NSString *reminderUnit; NSString *reminderRelation; NSString *reminderReference; + NSString *reminderAction; + BOOL reminderEmailOrganizer; + BOOL reminderEmailAttendees; /* ugly */ NSString *repeat; diff --git a/UI/Scheduler/UIxComponentEditor.m b/UI/Scheduler/UIxComponentEditor.m index 7e799ffa2..bb594b2db 100644 --- a/UI/Scheduler/UIxComponentEditor.m +++ b/UI/Scheduler/UIxComponentEditor.m @@ -62,6 +62,7 @@ #import #import #import +#import #import "../../Main/SOGo.h" @@ -180,6 +181,9 @@ iRANGE(2); reminderUnit = nil; reminderRelation = nil; reminderReference = nil; + reminderAction = nil; + reminderEmailOrganizer = NO; + reminderEmailAttendees = NO; repeatType = nil; repeat1 = nil; repeat2 = nil; @@ -462,8 +466,44 @@ iRANGE(2); } } +- (void) _loadEMailAlarm: (iCalAlarm *) anAlarm +{ + NSArray *attendees; + iCalPerson *aAttendee; + SOGoUser *owner; + NSString *ownerId, *email; + int count, max; + + attendees = [anAlarm attendees]; + reminderEmailOrganizer = NO; + reminderEmailAttendees = NO; + + ownerId = [[self clientObject] ownerInContext: nil]; + owner = [SOGoUser userWithLogin: ownerId]; + email = [[owner defaultIdentity] objectForKey: @"email"]; + + max = [attendees count]; + for (count = 0; + !(reminderEmailOrganizer && reminderEmailAttendees) + && count < max; + count++) + { + aAttendee = [attendees objectAtIndex: count]; + if ([[aAttendee rfc822Email] isEqualToString: email]) + reminderEmailOrganizer = YES; + else + reminderEmailAttendees = YES; + } +} + - (void) _loadAlarms { + iCalAlarm *anAlarm; + iCalTrigger *aTrigger; + NSString *duration, *quantity; + unichar c; + unsigned int i; + if ([component hasAlarms]) { // We currently have the following limitations for alarms: @@ -471,21 +511,17 @@ iRANGE(2); // - the alarm's action must be of type DISPLAY; // - the alarm's trigger value type must be DURATION. - iCalAlarm *anAlarm; - iCalTrigger *aTrigger; - NSString *duration, *quantity; - unichar c; - unsigned int i; - anAlarm = [[component alarms] objectAtIndex: 0]; aTrigger = [anAlarm trigger]; - if ([[anAlarm action] caseInsensitiveCompare: @"DISPLAY"] == NSOrderedSame && - [[aTrigger valueType] caseInsensitiveCompare: @"DURATION"] == NSOrderedSame) + ASSIGN (reminderAction, [[anAlarm action] lowercaseString]); + if (([reminderAction isEqualToString: @"display"] + || [reminderAction isEqualToString: @"email"]) + && [[aTrigger valueType] caseInsensitiveCompare: @"DURATION"] == NSOrderedSame) { duration = [aTrigger value]; i = [reminderValues indexOfObject: duration]; - if (i == NSNotFound) + if (i == NSNotFound || [reminderAction isEqualToString: @"email"]) { // Custom alarm ASSIGN (reminder, @"CUSTOM"); @@ -537,6 +573,9 @@ iRANGE(2); } if ([quantity length]) ASSIGN (reminderQuantity, quantity); + + if ([reminderAction isEqualToString: @"email"]) + [self _loadEMailAlarm: anAlarm]; } } else @@ -1046,6 +1085,36 @@ iRANGE(2); return text; } +- (void) setReminderAction: (NSString *) newValue +{ + ASSIGN (reminderAction, newValue); +} + +- (NSString *) reminderAction +{ + return reminderAction; +} + +- (void) setReminderEmailOrganizer: (NSString *) newValue +{ + reminderEmailOrganizer = [newValue isEqualToString: @"true"]; +} + +- (NSString *) reminderEmailOrganizer +{ + return (reminderEmailOrganizer ? @"true" : @"false"); +} + +- (void) setReminderEmailAttendees: (NSString *) newValue +{ + reminderEmailAttendees = [newValue isEqualToString: @"true"]; +} + +- (NSString *) reminderEmailAttendees +{ + return (reminderEmailAttendees ? @"true" : @"false"); +} + - (NSString *) repeat { return repeat; @@ -1983,6 +2052,41 @@ RANGE(2); } } +- (void) _appendAttendees: (NSArray *) attendees + toEmailAlarm: (iCalAlarm *) alarm +{ + NSMutableArray *aAttendees; + int count, max; + iCalPerson *currentAttendee, *aAttendee; + + max = [attendees count]; + aAttendees = [NSMutableArray arrayWithCapacity: max]; + for (count = 0; count < max; count++) + { + currentAttendee = [attendees objectAtIndex: count]; + aAttendee = [iCalPerson elementWithTag: @"attendee"]; + [aAttendee setCn: [currentAttendee cn]]; + [aAttendee setEmail: [currentAttendee rfc822Email]]; + [aAttendees addObject: aAttendee]; + } + [alarm setAttendees: aAttendees]; +} + +- (void) _appendOrganizerToEmailAlarm: (iCalAlarm *) alarm +{ + NSString *uid; + NSDictionary *ownerIdentity; + iCalPerson *aAttendee; + + uid = [[self clientObject] ownerInContext: context]; + ownerIdentity = [[SOGoUser userWithLogin: uid roles: nil] + defaultIdentity]; + aAttendee = [iCalPerson elementWithTag: @"attendee"]; + [aAttendee setCn: [ownerIdentity objectForKey: @"fullName"]]; + [aAttendee setEmail: [ownerIdentity objectForKey: @"email"]]; + [alarm addChild: aAttendee]; +} + - (void) takeValuesFromRequest: (WORequest *) _rq inContext: (WOContext *) _ctx { @@ -2020,23 +2124,36 @@ RANGE(2); iCalAlarm *anAlarm; NSString *aValue; unsigned int index; - + + anAlarm = [iCalAlarm new]; + index = [reminderItems indexOfObject: reminder]; - aValue = [reminderValues objectAtIndex: index]; aTrigger = [iCalTrigger elementWithTag: @"TRIGGER"]; [aTrigger setValueType: @"DURATION"]; - - anAlarm = [iCalAlarm new]; - [anAlarm setAction: @"DISPLAY"]; [anAlarm setTrigger: aTrigger]; + aValue = [reminderValues objectAtIndex: index]; if ([aValue length]) { // Predefined alarm + [anAlarm setAction: @"DISPLAY"]; [aTrigger setValue: aValue]; } else { // Custom alarm + [anAlarm setAction: [reminderAction uppercaseString]]; + if ([reminderAction isEqualToString: @"email"]) + { + [anAlarm removeAllAttendees]; + if (reminderEmailAttendees) + [self _appendAttendees: [component attendees] + toEmailAlarm: anAlarm]; + if (reminderEmailOrganizer) + [self _appendOrganizerToEmailAlarm: anAlarm]; + [anAlarm setSummary: [component summary]]; + [anAlarm setComment: [component comment]]; + } + if ([reminderReference caseInsensitiveCompare: @"BEFORE"] == NSOrderedSame) aValue = [NSString stringWithString: @"-P"]; else @@ -2277,6 +2394,17 @@ RANGE(2); return [self getEventRWType] != 0; } +- (NSString *) emailAlarmsEnabled +{ + SOGoSystemDefaults *sd; + + sd = [SOGoSystemDefaults sharedSystemDefaults]; + + return ([sd enableEMailAlarms] + ? @"true" + : @"false"); +} + - (BOOL) userHasRSVP { return ([self getEventRWType] == 1); diff --git a/UI/Scheduler/UIxReminderEditor.m b/UI/Scheduler/UIxReminderEditor.m index 65b3cdac0..1593a4bd1 100644 --- a/UI/Scheduler/UIxReminderEditor.m +++ b/UI/Scheduler/UIxReminderEditor.m @@ -23,7 +23,7 @@ #import #import -#import +#import #import "UIxReminderEditor.h" @@ -90,4 +90,13 @@ return text; } +- (BOOL) emailAlarmsEnabled +{ + SOGoSystemDefaults *sd; + + sd = [SOGoSystemDefaults sharedSystemDefaults]; + + return [sd enableEMailAlarms]; +} + @end diff --git a/UI/Scheduler/Ukrainian.lproj/Localizable.strings b/UI/Scheduler/Ukrainian.lproj/Localizable.strings index b09838aca..48a062718 100644 --- a/UI/Scheduler/Ukrainian.lproj/Localizable.strings +++ b/UI/Scheduler/Ukrainian.lproj/Localizable.strings @@ -406,6 +406,12 @@ "reminder_END" = "кінця події"; "Reminder Details" = "Деталі нагадування"; +"Choose a Reminder Action" = "Choose a Reminder Action"; +"Show an Alert" = "Show an Alert"; +"Send an E-mail" = "Send an E-mail"; +"Email Organizer" = "Email Organizer"; +"Email Attendees" = "Email Attendees"; + "zoom_400" = "400%"; "zoom_200" = "200%"; "zoom_100" = "100%"; diff --git a/UI/Scheduler/Welsh.lproj/Localizable.strings b/UI/Scheduler/Welsh.lproj/Localizable.strings index 8e94977fe..e23659d58 100644 --- a/UI/Scheduler/Welsh.lproj/Localizable.strings +++ b/UI/Scheduler/Welsh.lproj/Localizable.strings @@ -406,6 +406,12 @@ "reminder_END" = "the event ends"; "Reminder Details" = "Reminder Details"; +"Choose a Reminder Action" = "Choose a Reminder Action"; +"Show an Alert" = "Show an Alert"; +"Send an E-mail" = "Send an E-mail"; +"Email Organizer" = "Email Organizer"; +"Email Attendees" = "Email Attendees"; + "zoom_400" = "400%"; "zoom_200" = "200%"; "zoom_100" = "100%"; diff --git a/UI/Templates/SchedulerUI/UIxComponentEditor.wox b/UI/Templates/SchedulerUI/UIxComponentEditor.wox index 351d0b163..3d7cbcecb 100644 --- a/UI/Templates/SchedulerUI/UIxComponentEditor.wox +++ b/UI/Templates/SchedulerUI/UIxComponentEditor.wox @@ -21,6 +21,7 @@ const:negate="YES">false; var attendees = ; var ownerLogin = ''; + var emailAlarmsEnabled = ; var organizer = ;var owners = ; + + + @@ -328,6 +338,16 @@ id="reminderReference" var:value="reminderReference"/> + + + +
diff --git a/UI/Templates/SchedulerUI/UIxReminderEditor.wox b/UI/Templates/SchedulerUI/UIxReminderEditor.wox index 7d4beef40..50e7b2302 100644 --- a/UI/Templates/SchedulerUI/UIxReminderEditor.wox +++ b/UI/Templates/SchedulerUI/UIxReminderEditor.wox @@ -12,32 +12,44 @@ const:popup="YES">
-
- - - - -
- -
- -
-
- -
- - +
+
+ +
+ +
+ + +
+ +
+
+ +
+
+ +
+ + +
diff --git a/UI/WebServerResources/UIxComponentEditor.js b/UI/WebServerResources/UIxComponentEditor.js index dd301b27f..d2b7de620 100644 --- a/UI/WebServerResources/UIxComponentEditor.js +++ b/UI/WebServerResources/UIxComponentEditor.js @@ -373,10 +373,13 @@ function onPopupReminderWindow(event) { if (event) { if (ComponentEditor.reminderWindow && ComponentEditor.reminderWindow.open && !ComponentEditor.reminderWindow.closed) ComponentEditor.reminderWindow.focus(); - else - ComponentEditor.reminderWindow = window.open(ApplicationBaseURL + "editReminder", - sanitizeWindowName(activeCalendar + activeComponent + "Reminder"), - "width=250,height=150"); + else { + var height = (emailAlarmsEnabled ? 215 : 150); + ComponentEditor.reminderWindow + = window.open(ApplicationBaseURL + "editReminder", + sanitizeWindowName(activeCalendar + activeComponent + "Reminder"), + "width=255,height=" + height); + } } } else if (reminderHref) diff --git a/UI/WebServerResources/UIxReminderEditor.js b/UI/WebServerResources/UIxReminderEditor.js index 69e9a2ec5..f3d154245 100644 --- a/UI/WebServerResources/UIxReminderEditor.js +++ b/UI/WebServerResources/UIxReminderEditor.js @@ -6,7 +6,6 @@ function initializeWindowButtons() { cancelButton.observe("click", onEditorCancelClick, false); } - function initializeFormValues() { if (parent$("reminderUnit").value.length > 0) { $("quantityField").value = parent$("reminderQuantity").value; @@ -14,6 +13,33 @@ function initializeFormValues() { $("relationsList").value = parent$("reminderRelation").value; $("referencesList").value = parent$("reminderReference").value; } + + var actionList = $("actionList"); + if (actionList) { + actionList.observe("change", onActionListChange); + var action = parent$("reminderAction").value; + if (!action) + action = "display"; + actionList.value = action; + if (action == "email") { + $("emailOrganizer").checked = (parent$("reminderEmailOrganizer").value + == "true"); + $("emailAttendees").checked = (parent$("reminderEmailAttendees").value + == "true"); + } + updateActionCheckboxes(actionList); + } +} + +function onActionListChange() { + updateActionCheckboxes(this); +} + +function updateActionCheckboxes(list) { + var disabled = (list.value != "email"); + + $("emailOrganizer").disabled = disabled; + $("emailAttendees").disabled = disabled; } function onEditorOkClick(event) { @@ -24,6 +50,22 @@ function onEditorOkClick(event) { parent$("reminderRelation").value = $("relationsList").value; parent$("reminderReference").value = $("referencesList").value; + var actionList = $("actionList"); + var action; + if (actionList) { + action = $("actionList").value; + parent$("reminderEmailOrganizer").value = ($("emailOrganizer").checked + ? "true" + : "false"); + + parent$("reminderEmailAttendees").value = ($("emailAttendees").checked + ? "true" + : "false"); + } + else { + action = "display"; + } + parent$("reminderAction").value = action; window.close(); } else