From 5840f2a4a2d9f1612186dac8c454005aca949be4 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 19 Aug 2010 17:40:28 +0000 Subject: [PATCH] Monotone-Parent: c7c119b8830f974eae43854ab61fdff9fc0c72d3 Monotone-Revision: 5c82b99d5706b81d029752ca424be6a61a7cc96c Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2010-08-19T17:40:28 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 36 ++++ Main/SOGo.m | 9 + SoObjects/Appointments/GNUmakefile | 2 + .../Appointments/SOGoAppointmentObject.m | 32 ++-- .../Appointments/SOGoCalendarComponent.m | 32 ++++ Tools/GNUmakefile | 9 +- UI/Scheduler/UIxComponentEditor.h | 3 + UI/Scheduler/UIxComponentEditor.m | 156 ++++++++++++++++-- UI/Scheduler/UIxReminderEditor.m | 11 +- .../SchedulerUI/UIxComponentEditor.wox | 20 +++ .../SchedulerUI/UIxReminderEditor.wox | 64 ++++--- UI/WebServerResources/UIxComponentEditor.js | 11 +- UI/WebServerResources/UIxReminderEditor.js | 44 ++++- 13 files changed, 367 insertions(+), 62 deletions(-) diff --git a/ChangeLog b/ChangeLog index 61a7c8dc6..facd2f85d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,41 @@ 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. 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/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/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/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/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