diff --git a/ChangeLog b/ChangeLog index c24bd1cc0..90e353eeb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2008-11-17 Ludovic Marcotte + + * Added back the appointment update notification + templates from RC8 and updated them. + * SoObjects/Appointments/SOGoAppointmentFolder.m + Greatly improved the speed of getetag calls + * SoObjects/SOGo/SOGoGCSFolder.m + We now allow multiple users subscribe/unsubscribe + requests during one DAV call. + 2008-11-13 Ludovic Marcotte * SoObjects/Appointments/SOGoAppointmentObject.m diff --git a/SoObjects/Appointments/GNUmakefile b/SoObjects/Appointments/GNUmakefile index 801003f15..2093e4668 100644 --- a/SoObjects/Appointments/GNUmakefile +++ b/SoObjects/Appointments/GNUmakefile @@ -32,6 +32,7 @@ Appointments_OBJC_FILES = \ SOGoAptMailInvitation.m \ SOGoAptMailDeletion.m \ SOGoAptMailICalReply.m \ + SOGoAptMailUpdate.m \ Appointments_RESOURCE_FILES += \ Version \ @@ -45,21 +46,27 @@ Appointments_COMPONENTS += \ SOGoAptMailDutchInvitation.wo \ SOGoAptMailDutchICalReply.wo \ SOGoAptMailDutchDeletion.wo \ + SOGoAptMailDutchUpdate.wo \ SOGoAptMailEnglishInvitation.wo \ SOGoAptMailEnglishICalReply.wo \ SOGoAptMailEnglishDeletion.wo \ + SOGoAptMailEnglishUpdate.wo \ SOGoAptMailFrenchInvitation.wo \ SOGoAptMailFrenchICalReply.wo \ SOGoAptMailFrenchDeletion.wo \ + SOGoAptMailFrenchUpdate.wo \ SOGoAptMailGermanInvitation.wo \ SOGoAptMailGermanICalReply.wo \ SOGoAptMailGermanDeletion.wo \ + SOGoAptMailGermanUpdate.wo \ SOGoAptMailItalianInvitation.wo \ SOGoAptMailItalianICalReply.wo \ SOGoAptMailItalianDeletion.wo \ + SOGoAptMailItalianUpdate.wo \ SOGoAptMailSpanishInvitation.wo \ SOGoAptMailSpanishICalReply.wo \ SOGoAptMailSpanishDeletion.wo \ + SOGoAptMailSpanishUpdate.wo \ ADDITIONAL_INCLUDE_DIRS += -I../../SOPE/ diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index daf53f680..ce9193eb5 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -1005,19 +1005,19 @@ static Class sogoAppointmentFolderKlass = Nil; } - (void) _appendPropstat: (NSDictionary *) propstat - toResponse: (WOResponse *) r + toBuffer: (NSMutableString *) r { NSArray *properties; unsigned int count, max; - [r appendContentString: @""]; + [r appendString: @""]; properties = [propstat objectForKey: @"properties"]; max = [properties count]; for (count = 0; count < max; count++) - [r appendContentString: [properties objectAtIndex: count]]; - [r appendContentString: @""]; - [r appendContentString: [propstat objectForKey: @"status"]]; - [r appendContentString: @""]; + [r appendString: [properties objectAtIndex: count]]; + [r appendString: @""]; + [r appendString: [propstat objectForKey: @"status"]]; + [r appendString: @""]; } #warning we should use the EOFetchSpecification for that!!! (see doPROPFIND:) @@ -1062,11 +1062,12 @@ static Class sogoAppointmentFolderKlass = Nil; - (NSString **) _properties: (NSString **) properties ofObject: (NSDictionary *) object { + SOGoCalendarComponent *sogoObject; NSString **currentProperty; NSString **values, **currentValue; - SOGoObject *sogoObject; SoSecurityManager *mgr; SEL methodSel; + Class c; #warning things may crash here... values = calloc (100, sizeof (NSMutableString *)); @@ -1075,7 +1076,11 @@ static Class sogoAppointmentFolderKlass = Nil; #warning this check should be done directly in the query... we should fix this sometime mgr = [SoSecurityManager sharedSecurityManager]; - sogoObject = [self _createChildComponentWithRecord: object]; + + //c = [self objectClassForComponentName: [object objectForKey: @"c_component"]]; + sogoObject = [SOGoCalendarComponent objectWithRecord: object inContainer: self]; + [sogoObject setComponentTag: [object objectForKey: @"c_component"]]; + //sogoObject = [self _createChildComponentWithRecord: object]; if (activeUserIsOwner || [[self ownerInContext: context] @@ -1167,35 +1172,35 @@ static Class sogoAppointmentFolderKlass = Nil; - (void) appendObject: (NSDictionary *) object properties: (NSString **) properties withBaseURL: (NSString *) baseURL - toComplexResponse: (WOResponse *) r + toBuffer: (NSMutableString *) r { NSArray *propstats; unsigned int count, max; - [r appendContentString: @""]; - [r appendContentString: baseURL]; + [r appendFormat: @""]; + [r appendString: baseURL]; // if (![baseURL hasSuffix: @"/"]) // [r appendContentString: @"/"]; - [r appendContentString: [object objectForKey: @"c_name"]]; - [r appendContentString: @""]; + [r appendString: [object objectForKey: @"c_name"]]; + [r appendString: @""]; // NSLog (@"(appendPropstats...): %@", [NSDate date]); propstats = [self _propstats: properties ofObject: object]; max = [propstats count]; for (count = 0; count < max; count++) [self _appendPropstat: [propstats objectAtIndex: count] - toResponse: r]; + toBuffer: r]; // NSLog (@"/(appendPropstats...): %@", [NSDate date]); - [r appendContentString: @""]; + [r appendString: @""]; } - (void) appendMissingObjectRef: (NSString *) href - toComplexResponse: (WOResponse *) r + toBuffer: (NSMutableString *) r { - [r appendContentString: @""]; - [r appendContentString: href]; - [r appendContentString: @"HTTP/1.1 404 Not Found"]; + [r appendString: @""]; + [r appendString: href]; + [r appendString: @"HTTP/1.1 404 Not Found"]; } - (void) _appendTimeRange: (id ) timeRangeElement @@ -1452,33 +1457,48 @@ static Class sogoAppointmentFolderKlass = Nil; matchingFilters: (NSArray *) filters toResponse: (WOResponse *) response { - NSArray *apts; + NSArray *apts, *fields; NSDictionary *currentFilter; NSEnumerator *filterList; NSString *additionalFilters, *baseURL; + NSMutableString *buffer; unsigned int count, max; baseURL = [[self davURL] absoluteString]; - + + // We check if we need to fetch all fields. If the DAV client + // has only asked for {DAV:}getetag with no other properties, + // we do not load the c_content and other fields from the + // database as this can be pretty costly. + if ([*properties caseInsensitiveCompare: @"{DAV:}getetag"] == NSOrderedSame && + !*(properties+1)) + fields =[NSArray arrayWithObjects: @"c_name", @"c_version", + @"c_component", nil]; + else + fields = reportQueryFields; + filterList = [filters objectEnumerator]; while ((currentFilter = [filterList nextObject])) { additionalFilters = [self _composeAdditionalFilters: currentFilter]; -// NSLog(@"query"); - apts = [self bareFetchFields: reportQueryFields + NSLog(@"query"); + apts = [self bareFetchFields: fields from: [currentFilter objectForKey: @"start"] to: [currentFilter objectForKey: @"end"] title: [currentFilter objectForKey: @"title"] component: [currentFilter objectForKey: @"name"] additionalFilters: additionalFilters]; -// NSLog(@"adding properties"); + NSLog(@"adding properties"); max = [apts count]; + buffer = [[NSMutableString alloc] initWithCapacity: max*512]; for (count = 0; count < max; count++) [self appendObject: [apts objectAtIndex: count] properties: properties withBaseURL: baseURL - toComplexResponse: response]; -// NSLog(@"done"); + toBuffer: buffer]; + NSLog(@"done"); + [response appendContentString: buffer]; + [buffer release]; } } @@ -1640,6 +1660,7 @@ static Class sogoAppointmentFolderKlass = Nil; NSDictionary *currentComponent, *components; NSString *currentURL, *baseURL; NSMutableArray *urls; + NSMutableString *buffer; unsigned int count, max; baseURL = [[self davURL] absoluteString]; @@ -1656,6 +1677,7 @@ static Class sogoAppointmentFolderKlass = Nil; components = [self _fetchComponentsMatchingURLs: urls]; max = [urls count]; // NSLog (@"adding properties with url"); + buffer = [[NSMutableString alloc] initWithCapacity: max*512]; for (count = 0; count < max; count++) { currentComponent @@ -1664,11 +1686,13 @@ static Class sogoAppointmentFolderKlass = Nil; [self appendObject: currentComponent properties: properties withBaseURL: baseURL - toComplexResponse: response]; + toBuffer: buffer]; else [self appendMissingObjectRef: currentURL - toComplexResponse: response]; + toBuffer: buffer]; } + [response appendContentString: buffer]; + [buffer release]; // NSLog (@"/adding properties with url"); [urls release]; diff --git a/SoObjects/Appointments/SOGoAppointmentObject.m b/SoObjects/Appointments/SOGoAppointmentObject.m index 31ec2ef0c..bd75fd20d 100644 --- a/SoObjects/Appointments/SOGoAppointmentObject.m +++ b/SoObjects/Appointments/SOGoAppointmentObject.m @@ -269,8 +269,9 @@ forUID: currentUID]; } - [self sendEMailUsingTemplateNamed: @"Invitation" + [self sendEMailUsingTemplateNamed: @"Update" forObject: [newEvent itipEntryWithMethod: @"request"] + previousObject: oldEvent toAttendees: updateAttendees]; } @@ -304,6 +305,7 @@ [self _handleRemovedUsers: attendees]; [self sendEMailUsingTemplateNamed: @"Deletion" forObject: [newEvent itipEntryWithMethod: @"cancel"] + previousObject: oldEvent toAttendees: attendees]; } @@ -324,6 +326,7 @@ [self _handleAddedUsers: attendees fromEvent: newEvent]; [self sendEMailUsingTemplateNamed: @"Invitation" forObject: [newEvent itipEntryWithMethod: @"request"] + previousObject: oldEvent toAttendees: attendees]; } } @@ -349,6 +352,7 @@ [self _handleAddedUsers: attendees fromEvent: newEvent]; [self sendEMailUsingTemplateNamed: @"Invitation" forObject: [newEvent itipEntryWithMethod: @"request"] + previousObject: oldEvent toAttendees: attendees]; } @@ -438,8 +442,8 @@ statusChange: (NSString *) newStatus inEvent: (iCalEvent *) event { - NSString *newContent, *currentStatus, *currentUser, *organizerUID; - SOGoUser *ownerUser; + NSString *newContent, *currentStatus, *organizerUID; + SOGoUser *ownerUser, *currentUser; NSException *ex; ex = nil; @@ -571,6 +575,7 @@ #warning fix this when sendEmailUsing blabla has been cleaned up [self sendEMailUsingTemplateNamed: @"Invitation" forObject: event + previousObject: nil toAttendees: [NSArray arrayWithObject: person]]; [person release]; [elements @@ -604,6 +609,7 @@ #warning fix this when sendEmailUsing blabla has been cleaned up [self sendEMailUsingTemplateNamed: @"Deletion" forObject: event + previousObject: nil toAttendees: [NSArray arrayWithObject: person]]; [person release]; [elements @@ -805,6 +811,7 @@ [self _handleRemovedUsers: attendees]; [self sendEMailUsingTemplateNamed: @"Deletion" forObject: [occurence itipEntryWithMethod: @"cancel"] + previousObject: nil toAttendees: attendees]; } } diff --git a/SoObjects/Appointments/SOGoAptMailDutchUpdate.wo/SOGoAptMailDutchUpdate.html b/SoObjects/Appointments/SOGoAptMailDutchUpdate.wo/SOGoAptMailDutchUpdate.html new file mode 100644 index 000000000..ae08537cb --- /dev/null +++ b/SoObjects/Appointments/SOGoAptMailDutchUpdate.wo/SOGoAptMailDutchUpdate.html @@ -0,0 +1,5 @@ +<#IsSubject>The appointment for the <#OldAptStartDate /> at <#OldAptStartTime /> has changed +<#IsBody> +This appointment, previously set for <#OldAptStartDate /> at <#OldAptStartTime /> (<#OldAptLocation />) is now scheduled for <#NewAptStartDate /> at <#NewAptStartTime /> (<#NewAptLocation />). +Please make a decision for these new settings. + diff --git a/SoObjects/Appointments/SOGoAptMailDutchUpdate.wo/SOGoAptMailDutchUpdate.wod b/SoObjects/Appointments/SOGoAptMailDutchUpdate.wo/SOGoAptMailDutchUpdate.wod new file mode 100644 index 000000000..bc8d38a29 --- /dev/null +++ b/SoObjects/Appointments/SOGoAptMailDutchUpdate.wo/SOGoAptMailDutchUpdate.wod @@ -0,0 +1,47 @@ +OldAptStartDate: WOString { + value = oldStartDate; + dateformat = "%d/%m/%y"; + escapeHTML = NO; +} + +OldAptStartTime: WOString { + value = oldStartDate; + dateformat = "%H:%M"; + escapeHTML = NO; +} + +NewAptStartDate: WOString { + value = newStartDate; + dateformat = "%d/%m/%y"; + escapeHTML = NO; +} + +NewAptStartTime: WOString { + value = newStartDate; + dateformat = "%H:%M"; + escapeHTML = NO; +} + +Organizer: WOString { + value = organizerName; + escapeHTML = NO; +} + +OldAptLocation: WOString { + value = previousApt.location; + escapeHTML = NO; +} + +NewAptLocation: WOString { + value = apt.location; + escapeHTML = NO; +} + +IsSubject: WOConditional { + condition = isSubject; +} + +IsBody: WOConditional { + condition = isSubject; + negate = YES; +} diff --git a/SoObjects/Appointments/SOGoAptMailEnglishUpdate.wo/SOGoAptMailEnglishUpdate.html b/SoObjects/Appointments/SOGoAptMailEnglishUpdate.wo/SOGoAptMailEnglishUpdate.html new file mode 100644 index 000000000..ae08537cb --- /dev/null +++ b/SoObjects/Appointments/SOGoAptMailEnglishUpdate.wo/SOGoAptMailEnglishUpdate.html @@ -0,0 +1,5 @@ +<#IsSubject>The appointment for the <#OldAptStartDate /> at <#OldAptStartTime /> has changed +<#IsBody> +This appointment, previously set for <#OldAptStartDate /> at <#OldAptStartTime /> (<#OldAptLocation />) is now scheduled for <#NewAptStartDate /> at <#NewAptStartTime /> (<#NewAptLocation />). +Please make a decision for these new settings. + diff --git a/SoObjects/Appointments/SOGoAptMailEnglishUpdate.wo/SOGoAptMailEnglishUpdate.wod b/SoObjects/Appointments/SOGoAptMailEnglishUpdate.wo/SOGoAptMailEnglishUpdate.wod new file mode 100644 index 000000000..bc8d38a29 --- /dev/null +++ b/SoObjects/Appointments/SOGoAptMailEnglishUpdate.wo/SOGoAptMailEnglishUpdate.wod @@ -0,0 +1,47 @@ +OldAptStartDate: WOString { + value = oldStartDate; + dateformat = "%d/%m/%y"; + escapeHTML = NO; +} + +OldAptStartTime: WOString { + value = oldStartDate; + dateformat = "%H:%M"; + escapeHTML = NO; +} + +NewAptStartDate: WOString { + value = newStartDate; + dateformat = "%d/%m/%y"; + escapeHTML = NO; +} + +NewAptStartTime: WOString { + value = newStartDate; + dateformat = "%H:%M"; + escapeHTML = NO; +} + +Organizer: WOString { + value = organizerName; + escapeHTML = NO; +} + +OldAptLocation: WOString { + value = previousApt.location; + escapeHTML = NO; +} + +NewAptLocation: WOString { + value = apt.location; + escapeHTML = NO; +} + +IsSubject: WOConditional { + condition = isSubject; +} + +IsBody: WOConditional { + condition = isSubject; + negate = YES; +} diff --git a/SoObjects/Appointments/SOGoAptMailFrenchUpdate.wo/SOGoAptMailFrenchUpdate.html b/SoObjects/Appointments/SOGoAptMailFrenchUpdate.wo/SOGoAptMailFrenchUpdate.html new file mode 100644 index 000000000..31d34605d --- /dev/null +++ b/SoObjects/Appointments/SOGoAptMailFrenchUpdate.wo/SOGoAptMailFrenchUpdate.html @@ -0,0 +1,5 @@ +<#IsSubject>Le rendez-vous du <#OldAptStartDate /> à <#OldAptStartTime /> est modifié +<#IsBody> +La réunion qui devait se dérouler le <#OldAptStartDate /> à <#OldAptStartTime /> (<#OldAptLocation />) est maintenant prévue le <#NewAptStartDate /> à <#NewAptStartTime /> (<#NewAptLocation />). +Vous êtes invité à accepter ou refuser de participer à la réunion pour cette nouvelle date. + diff --git a/SoObjects/Appointments/SOGoAptMailFrenchUpdate.wo/SOGoAptMailFrenchUpdate.wod b/SoObjects/Appointments/SOGoAptMailFrenchUpdate.wo/SOGoAptMailFrenchUpdate.wod new file mode 100644 index 000000000..bc8d38a29 --- /dev/null +++ b/SoObjects/Appointments/SOGoAptMailFrenchUpdate.wo/SOGoAptMailFrenchUpdate.wod @@ -0,0 +1,47 @@ +OldAptStartDate: WOString { + value = oldStartDate; + dateformat = "%d/%m/%y"; + escapeHTML = NO; +} + +OldAptStartTime: WOString { + value = oldStartDate; + dateformat = "%H:%M"; + escapeHTML = NO; +} + +NewAptStartDate: WOString { + value = newStartDate; + dateformat = "%d/%m/%y"; + escapeHTML = NO; +} + +NewAptStartTime: WOString { + value = newStartDate; + dateformat = "%H:%M"; + escapeHTML = NO; +} + +Organizer: WOString { + value = organizerName; + escapeHTML = NO; +} + +OldAptLocation: WOString { + value = previousApt.location; + escapeHTML = NO; +} + +NewAptLocation: WOString { + value = apt.location; + escapeHTML = NO; +} + +IsSubject: WOConditional { + condition = isSubject; +} + +IsBody: WOConditional { + condition = isSubject; + negate = YES; +} diff --git a/SoObjects/Appointments/SOGoAptMailGermanUpdate.wo/SOGoAptMailGermanUpdate.html b/SoObjects/Appointments/SOGoAptMailGermanUpdate.wo/SOGoAptMailGermanUpdate.html new file mode 100644 index 000000000..ae08537cb --- /dev/null +++ b/SoObjects/Appointments/SOGoAptMailGermanUpdate.wo/SOGoAptMailGermanUpdate.html @@ -0,0 +1,5 @@ +<#IsSubject>The appointment for the <#OldAptStartDate /> at <#OldAptStartTime /> has changed +<#IsBody> +This appointment, previously set for <#OldAptStartDate /> at <#OldAptStartTime /> (<#OldAptLocation />) is now scheduled for <#NewAptStartDate /> at <#NewAptStartTime /> (<#NewAptLocation />). +Please make a decision for these new settings. + diff --git a/SoObjects/Appointments/SOGoAptMailGermanUpdate.wo/SOGoAptMailGermanUpdate.wod b/SoObjects/Appointments/SOGoAptMailGermanUpdate.wo/SOGoAptMailGermanUpdate.wod new file mode 100644 index 000000000..bc8d38a29 --- /dev/null +++ b/SoObjects/Appointments/SOGoAptMailGermanUpdate.wo/SOGoAptMailGermanUpdate.wod @@ -0,0 +1,47 @@ +OldAptStartDate: WOString { + value = oldStartDate; + dateformat = "%d/%m/%y"; + escapeHTML = NO; +} + +OldAptStartTime: WOString { + value = oldStartDate; + dateformat = "%H:%M"; + escapeHTML = NO; +} + +NewAptStartDate: WOString { + value = newStartDate; + dateformat = "%d/%m/%y"; + escapeHTML = NO; +} + +NewAptStartTime: WOString { + value = newStartDate; + dateformat = "%H:%M"; + escapeHTML = NO; +} + +Organizer: WOString { + value = organizerName; + escapeHTML = NO; +} + +OldAptLocation: WOString { + value = previousApt.location; + escapeHTML = NO; +} + +NewAptLocation: WOString { + value = apt.location; + escapeHTML = NO; +} + +IsSubject: WOConditional { + condition = isSubject; +} + +IsBody: WOConditional { + condition = isSubject; + negate = YES; +} diff --git a/SoObjects/Appointments/SOGoAptMailItalianUpdate.wo/SOGoAptMailItalianUpdate.html b/SoObjects/Appointments/SOGoAptMailItalianUpdate.wo/SOGoAptMailItalianUpdate.html new file mode 100644 index 000000000..cce2fa90f --- /dev/null +++ b/SoObjects/Appointments/SOGoAptMailItalianUpdate.wo/SOGoAptMailItalianUpdate.html @@ -0,0 +1,8 @@ +<#IsSubject>L'appuntamento fissato in data <#OldAptStartDate /> alle ore <#OldAptStartTime /> è stato modificato +<#IsBody> +Questo appuntamento, fissato precedentemete in data <#OldAptStartDate /> (<#OldAptLocation />) +alle ore <#OldAptStartTime /> è ora programmato il <#NewAptStartDate +/> alle ore <#NewAptStartTime +/> (<#NewAptLocation />) +Per confermare o disdire. + diff --git a/SoObjects/Appointments/SOGoAptMailItalianUpdate.wo/SOGoAptMailItalianUpdate.wod b/SoObjects/Appointments/SOGoAptMailItalianUpdate.wo/SOGoAptMailItalianUpdate.wod new file mode 100644 index 000000000..bc8d38a29 --- /dev/null +++ b/SoObjects/Appointments/SOGoAptMailItalianUpdate.wo/SOGoAptMailItalianUpdate.wod @@ -0,0 +1,47 @@ +OldAptStartDate: WOString { + value = oldStartDate; + dateformat = "%d/%m/%y"; + escapeHTML = NO; +} + +OldAptStartTime: WOString { + value = oldStartDate; + dateformat = "%H:%M"; + escapeHTML = NO; +} + +NewAptStartDate: WOString { + value = newStartDate; + dateformat = "%d/%m/%y"; + escapeHTML = NO; +} + +NewAptStartTime: WOString { + value = newStartDate; + dateformat = "%H:%M"; + escapeHTML = NO; +} + +Organizer: WOString { + value = organizerName; + escapeHTML = NO; +} + +OldAptLocation: WOString { + value = previousApt.location; + escapeHTML = NO; +} + +NewAptLocation: WOString { + value = apt.location; + escapeHTML = NO; +} + +IsSubject: WOConditional { + condition = isSubject; +} + +IsBody: WOConditional { + condition = isSubject; + negate = YES; +} diff --git a/SoObjects/Appointments/SOGoAptMailNotification.h b/SoObjects/Appointments/SOGoAptMailNotification.h index 9774c809b..6fa938eda 100644 --- a/SoObjects/Appointments/SOGoAptMailNotification.h +++ b/SoObjects/Appointments/SOGoAptMailNotification.h @@ -34,7 +34,8 @@ */ @interface SOGoAptMailNotification : SoComponent { - iCalEntityObject* apt; + iCalEntityObject *apt; + iCalEntityObject *previousApt; NSString *homePageURL; NSTimeZone *viewTZ; NSCalendarDate *oldStartDate; @@ -44,9 +45,16 @@ } - (iCalEntityObject *) apt; -- (void) setApt: (iCalEntityObject *) newApt; +- (void) setApt: (iCalEntityObject *) theApt; -/* Content Generation */ +- (iCalEntityObject *) previousApt; +- (void) setPreviousApt: (iCalEntityObject *) theApt; + +- (void) setOrganizerName: (NSString *) theString; +- (NSString *) organizerName; + +- (BOOL) hasSentBy; +- (NSString *) sentBy; - (NSString *) getSubject; - (NSString *) getBody; diff --git a/SoObjects/Appointments/SOGoAptMailNotification.m b/SoObjects/Appointments/SOGoAptMailNotification.m index d62cc16f1..845011ba3 100644 --- a/SoObjects/Appointments/SOGoAptMailNotification.m +++ b/SoObjects/Appointments/SOGoAptMailNotification.m @@ -68,7 +68,11 @@ static NSTimeZone *UTC = nil; - (void) dealloc { [apt release]; + [previousApt release]; [organizerName release]; + [viewTZ release]; + [oldStartDate release]; + [newStartDate release]; [super dealloc]; } @@ -77,11 +81,50 @@ static NSTimeZone *UTC = nil; return apt; } -- (void) setApt: (iCalEntityObject *) newApt +- (void) setApt: (iCalEntityObject *) theApt { - ASSIGN (apt, newApt); + ASSIGN(apt, theApt); } +- (iCalEntityObject *) previousApt +{ + return previousApt; +} + +- (void) setPreviousApt: (iCalEntityObject *) theApt +{ + ASSIGN(previousApt, theApt); +} + +- (NSTimeZone *) viewTZ +{ + if (self->viewTZ) return self->viewTZ; + return UTC; +} +- (void) setViewTZ: (NSTimeZone *) _viewTZ +{ + ASSIGN(self->viewTZ, _viewTZ); +} + +- (NSCalendarDate *) oldStartDate +{ + if (!self->oldStartDate) + { + ASSIGN(self->oldStartDate, [[self previousApt] startDate]); + [self->oldStartDate setTimeZone: [self viewTZ]]; + } + return self->oldStartDate; +} + +- (NSCalendarDate *) newStartDate +{ + if (!self->newStartDate) + { + ASSIGN(self->newStartDate, [[self apt] startDate]); + [self->newStartDate setTimeZone:[self viewTZ]]; + } + return self->newStartDate; +} - (BOOL) isSubject { diff --git a/SoObjects/Appointments/SOGoAptMailSpanishUpdate.wo/SOGoAptMailSpanishUpdate.html b/SoObjects/Appointments/SOGoAptMailSpanishUpdate.wo/SOGoAptMailSpanishUpdate.html new file mode 100644 index 000000000..ae08537cb --- /dev/null +++ b/SoObjects/Appointments/SOGoAptMailSpanishUpdate.wo/SOGoAptMailSpanishUpdate.html @@ -0,0 +1,5 @@ +<#IsSubject>The appointment for the <#OldAptStartDate /> at <#OldAptStartTime /> has changed +<#IsBody> +This appointment, previously set for <#OldAptStartDate /> at <#OldAptStartTime /> (<#OldAptLocation />) is now scheduled for <#NewAptStartDate /> at <#NewAptStartTime /> (<#NewAptLocation />). +Please make a decision for these new settings. + diff --git a/SoObjects/Appointments/SOGoAptMailSpanishUpdate.wo/SOGoAptMailSpanishUpdate.wod b/SoObjects/Appointments/SOGoAptMailSpanishUpdate.wo/SOGoAptMailSpanishUpdate.wod new file mode 100644 index 000000000..bc8d38a29 --- /dev/null +++ b/SoObjects/Appointments/SOGoAptMailSpanishUpdate.wo/SOGoAptMailSpanishUpdate.wod @@ -0,0 +1,47 @@ +OldAptStartDate: WOString { + value = oldStartDate; + dateformat = "%d/%m/%y"; + escapeHTML = NO; +} + +OldAptStartTime: WOString { + value = oldStartDate; + dateformat = "%H:%M"; + escapeHTML = NO; +} + +NewAptStartDate: WOString { + value = newStartDate; + dateformat = "%d/%m/%y"; + escapeHTML = NO; +} + +NewAptStartTime: WOString { + value = newStartDate; + dateformat = "%H:%M"; + escapeHTML = NO; +} + +Organizer: WOString { + value = organizerName; + escapeHTML = NO; +} + +OldAptLocation: WOString { + value = previousApt.location; + escapeHTML = NO; +} + +NewAptLocation: WOString { + value = apt.location; + escapeHTML = NO; +} + +IsSubject: WOConditional { + condition = isSubject; +} + +IsBody: WOConditional { + condition = isSubject; + negate = YES; +} diff --git a/SoObjects/Appointments/SOGoAptMailUpdate.m b/SoObjects/Appointments/SOGoAptMailUpdate.m new file mode 100644 index 000000000..3ff6ff326 --- /dev/null +++ b/SoObjects/Appointments/SOGoAptMailUpdate.m @@ -0,0 +1,57 @@ +/* + Copyright (C) 2000-2005 SKYRIX Software AG + + This file is part of OpenGroupware.org. + + OGo is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + OGo 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 Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with OGo; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ + +#include "SOGoAptMailNotification.h" + +@interface SOGoAptMailEnglishUpdate : SOGoAptMailNotification +{ +} +@end + +@implementation SOGoAptMailEnglishUpdate +@end + +@interface SOGoAptMailFrenchUpdate : SOGoAptMailNotification +{ +} +@end + +@implementation SOGoAptMailFrenchUpdate +@end + + +@interface SOGoAptMailGermanUpdate : SOGoAptMailNotification +{ +} +@end + +@implementation SOGoAptMailGermanUpdate +@end + + +@interface SOGoAptMailItalianUpdate : SOGoAptMailNotification +{ +} +@end + +@implementation SOGoAptMailItalianUpdate +@end + diff --git a/SoObjects/Appointments/SOGoCalendarComponent.h b/SoObjects/Appointments/SOGoCalendarComponent.h index a60ed016b..d2be267e9 100644 --- a/SoObjects/Appointments/SOGoCalendarComponent.h +++ b/SoObjects/Appointments/SOGoCalendarComponent.h @@ -42,9 +42,11 @@ iCalCalendar *fullCalendar; iCalCalendar *safeCalendar; iCalCalendar *originalCalendar; + NSString *componentTag; } - (NSString *) componentTag; +- (void) setComponentTag: (NSString *) theTag; - (iCalCalendar *) calendar: (BOOL) create secure: (BOOL) secure; @@ -61,6 +63,7 @@ - (BOOL) sendEMailNotifications; - (void) sendEMailUsingTemplateNamed: (NSString *) pageName forObject: (iCalRepeatableEntityObject *) object + previousObject: (iCalRepeatableEntityObject *) previousObject toAttendees: (NSArray *) attendees; - (void) sendIMIPReplyForEvent: (iCalRepeatableEntityObject *) event from: (SOGoUser *) from diff --git a/SoObjects/Appointments/SOGoCalendarComponent.m b/SoObjects/Appointments/SOGoCalendarComponent.m index 7973380ed..eabb610ae 100644 --- a/SoObjects/Appointments/SOGoCalendarComponent.m +++ b/SoObjects/Appointments/SOGoCalendarComponent.m @@ -83,6 +83,7 @@ static BOOL sendEMailNotifications = NO; fullCalendar = nil; safeCalendar = nil; originalCalendar = nil; + componentTag = nil; } return self; @@ -93,6 +94,7 @@ static BOOL sendEMailNotifications = NO; [fullCalendar release]; [safeCalendar release]; [originalCalendar release]; + [componentTag release]; [super dealloc]; } @@ -103,9 +105,15 @@ static BOOL sendEMailNotifications = NO; - (NSString *) componentTag { - [self subclassResponsibility: _cmd]; + if (!componentTag) + [self subclassResponsibility: _cmd]; - return nil; + return componentTag; +} + +- (void) setComponentTag: (NSString *) theTag +{ + ASSIGN(componentTag, theTag); } - (void) _filterComponent: (iCalEntityObject *) component @@ -326,10 +334,9 @@ _occurenceHasID (iCalRepeatableEntityObject *occurence, NSString *recID) - (iCalCalendar *) calendar: (BOOL) create secure: (BOOL) secure { - NSString *componentTag; iCalRepeatableEntityObject *newComponent; iCalCalendar **calendar, *returnedCopy; - NSString *iCalString; + NSString *iCalString, *tag; if (secure) calendar = &safeCalendar; @@ -356,9 +363,9 @@ _occurenceHasID (iCalRepeatableEntityObject *occurence, NSString *recID) ASSIGN (*calendar, [iCalCalendar groupWithTag: @"vcalendar"]); [*calendar setVersion: @"2.0"]; [*calendar setProdID: @"-//Inverse inc.//SOGo 0.9//EN"]; - componentTag = [[self componentTag] uppercaseString]; - newComponent = [[*calendar classForTag: componentTag] - groupWithTag: componentTag]; + tag = [[self componentTag] uppercaseString]; + newComponent = [[*calendar classForTag: tag] + groupWithTag: tag]; [newComponent setUid: [self globallyUniqueObjectId]]; [*calendar addChild: newComponent]; } @@ -453,6 +460,7 @@ _occurenceHasID (iCalRepeatableEntityObject *occurence, NSString *recID) - (void) sendEMailUsingTemplateNamed: (NSString *) newPageName forObject: (iCalRepeatableEntityObject *) object + previousObject: (iCalRepeatableEntityObject *) previousObject toAttendees: (NSArray *) attendees { NSString *pageName; @@ -467,7 +475,7 @@ _occurenceHasID (iCalRepeatableEntityObject *occurence, NSString *recID) NGMimeMessage *msg; NGMimeBodyPart *bodyPart; NGMimeMultipartBody *body; - SOGoUser *ownerUser, *currentUser; + SOGoUser *ownerUser; if (sendEMailNotifications && [object isStillRelevant]) @@ -511,6 +519,7 @@ _occurenceHasID (iCalRepeatableEntityObject *occurence, NSString *recID) /* construct message content */ p = [app pageWithName: pageName inContext: context]; [p setApt: object]; + [p setPreviousApt: previousObject]; if ([[object organizer] cn] && [[[object organizer] cn] length]) { diff --git a/SoObjects/SOGo/SOGoGCSFolder.h b/SoObjects/SOGo/SOGoGCSFolder.h index 600345f45..fcf11cd8c 100644 --- a/SoObjects/SOGo/SOGoGCSFolder.h +++ b/SoObjects/SOGo/SOGoGCSFolder.h @@ -84,7 +84,7 @@ - (void) renameTo: (NSString *) newName; - (WOResponse *) subscribe: (BOOL) reallyDo - inTheNameOf: (NSString *) delegatedUser + inTheNamesOf: (NSArray *) delegatedUsers fromMailInvitation: (BOOL) isMailInvitation inContext: (WOContext *) localContext; diff --git a/SoObjects/SOGo/SOGoGCSFolder.m b/SoObjects/SOGo/SOGoGCSFolder.m index 80e2a8b5b..32290caa5 100644 --- a/SoObjects/SOGo/SOGoGCSFolder.m +++ b/SoObjects/SOGo/SOGoGCSFolder.m @@ -660,59 +660,72 @@ static NSArray *childRecordFields = nil; } - (WOResponse *) subscribe: (BOOL) reallyDo - inTheNameOf: (NSString *) delegatedUser + inTheNamesOf: (NSArray *) delegatedUsers fromMailInvitation: (BOOL) isMailInvitation inContext: (WOContext *) localContext { WOResponse *response; - SOGoUser *currentUser, *subscriptionUser; - BOOL validRequest; + SOGoUser *currentUser; response = [localContext response]; currentUser = [localContext activeUser]; - if ([delegatedUser length]) + if (delegatedUsers && [delegatedUsers count]) { - validRequest = ([currentUser isSuperUser]); - subscriptionUser = [SOGoUser userWithLogin: delegatedUser roles: nil]; - } - else - { - validRequest = YES; - subscriptionUser = currentUser; - } + if (![currentUser isSuperUser]) + { + [response setStatus: 403]; + [response appendContentString: + @"You cannot subscribe another user to any folder" + @" unless you are a super-user."]; + } + else + { + SOGoUser *subscriptionUser; + int i; - if (validRequest) - [self _subscribeUser: subscriptionUser - reallyDo: reallyDo - fromMailInvitation: isMailInvitation - inResponse: response]; + for (i = 0; i < [delegatedUsers count]; i++) + { + subscriptionUser = [SOGoUser userWithLogin: [delegatedUsers objectAtIndex: i] + roles: nil]; + + [self _subscribeUser: subscriptionUser + reallyDo: reallyDo + fromMailInvitation: isMailInvitation + inResponse: response]; + } + } + } else { - [response setStatus: 403]; - [response appendContentString: - @"You cannot subscribe another user to any folder" - @" unless you are a super-user."]; + [self _subscribeUser: currentUser + reallyDo: reallyDo + fromMailInvitation: isMailInvitation + inResponse: response]; } return response; } -- (NSString *) _parseDAVDelegatedUser: (WOContext *) queryContext +- (NSArray *) _parseDAVDelegatedUser: (WOContext *) queryContext { id document; id attrs; - + id o; document = [[queryContext request] contentAsDOMDocument]; attrs = [[document documentElement] attributes]; - return [[attrs namedItem: @"user"] nodeValue]; + o = [attrs namedItem: @"users"]; + + if (o) return [[o nodeValue] componentsSeparatedByString: @","]; + + return nil; } - (id ) davSubscribe: (WOContext *) queryContext { return [self subscribe: YES - inTheNameOf: [self _parseDAVDelegatedUser: queryContext] + inTheNamesOf: [self _parseDAVDelegatedUser: queryContext] fromMailInvitation: NO inContext: queryContext]; } @@ -720,7 +733,7 @@ static NSArray *childRecordFields = nil; - (id ) davUnsubscribe: (WOContext *) queryContext { return [self subscribe: NO - inTheNameOf: [self _parseDAVDelegatedUser: queryContext] + inTheNamesOf: [self _parseDAVDelegatedUser: queryContext] fromMailInvitation: NO inContext: queryContext]; } diff --git a/UI/Common/UIxFolderActions.m b/UI/Common/UIxFolderActions.m index edce5a18b..fd586ab1f 100644 --- a/UI/Common/UIxFolderActions.m +++ b/UI/Common/UIxFolderActions.m @@ -81,7 +81,7 @@ [self _setupContext]; return [clientObject subscribe: YES - inTheNameOf: nil + inTheNamesOf: nil fromMailInvitation: isMailInvitation inContext: context]; } @@ -91,7 +91,7 @@ [self _setupContext]; return [clientObject subscribe: NO - inTheNameOf: nil + inTheNamesOf: nil fromMailInvitation: isMailInvitation inContext: context]; }