AD85C72807C4E8740036AC7A /* ChangeLog */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 8; lastKnownFileType = text; path = ChangeLog; sourceTree = "<group>"; tabWidth = 8; usesTabs = 1; };
AD85C72907C4E8740036AC7A /* NSString+iCal.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = "NSString+iCal.h"; sourceTree = "<group>"; };
AD85C72A07C4E8740036AC7A /* SOGoAppointment.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = SOGoAppointment.h; sourceTree = "<group>"; };
- AD85C72B07C4E8740036AC7A /* SOGoAppointment.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = SOGoAppointment.m; sourceTree = "<group>"; };
+ AD85C72B07C4E8740036AC7A /* SOGoAppointment.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = SOGoAppointment.m; sourceTree = "<group>"; tabWidth = 2; };
AD85C72C07C4E8740036AC7A /* SOGoAppointmentICalRenderer.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = SOGoAppointmentICalRenderer.h; sourceTree = "<group>"; };
AD85C72D07C4E8740036AC7A /* SOGoAppointmentICalRenderer.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = SOGoAppointmentICalRenderer.m; sourceTree = "<group>"; };
AD85C72E07C4E8740036AC7A /* SOGoCustomGroupFolder.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = SOGoCustomGroupFolder.h; sourceTree = "<group>"; };
ADA63205071330AE0058C21C /* SOGoAppointment+UIx.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = "SOGoAppointment+UIx.h"; sourceTree = "<group>"; };
ADA63206071330AE0058C21C /* SOGoAppointment+UIx.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = "SOGoAppointment+UIx.m"; sourceTree = "<group>"; };
ADAD40CA0769FFD000AAD24E /* UIxCalInlineAptView.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = UIxCalInlineAptView.m; sourceTree = "<group>"; };
+ ADB742000887C90200AC849E /* SOGoAptMailRemoval.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOGoAptMailRemoval.m; sourceTree = "<group>"; };
+ ADB742040887C93100AC849E /* SOGoAptMailRemoval.wo */ = {isa = PBXFileReference; lastKnownFileType = folder; path = SOGoAptMailRemoval.wo; sourceTree = "<group>"; };
+ ADB7420B0887C94C00AC849E /* SOGoAptMailDeletion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOGoAptMailDeletion.m; sourceTree = "<group>"; };
+ ADB7420C0887C95A00AC849E /* SOGoAptMailDeletion.wo */ = {isa = PBXFileReference; lastKnownFileType = folder; path = SOGoAptMailDeletion.wo; sourceTree = "<group>"; };
ADB79CAD07D4BF1600CA782A /* ChangeLog */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 8; lastKnownFileType = text; path = ChangeLog; sourceTree = "<group>"; tabWidth = 8; usesTabs = 1; };
ADB7A0FC07D6389500CA782A /* NSObject+AptComparison.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = "NSObject+AptComparison.h"; sourceTree = "<group>"; };
ADB7A0FD07D6389500CA782A /* NSObject+AptComparison.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = "NSObject+AptComparison.m"; sourceTree = "<group>"; };
AD2FA8720883B9FE009A91E7 /* SOGoAptMailNotification */,
AD2FA8DA0883CCF0009A91E7 /* SOGoAptMailInvitation */,
AD2FA9C40883F922009A91E7 /* SOGoAptMailUpdate */,
+ ADB741FF0887C90200AC849E /* SOGoAptMailRemoval */,
+ ADB7420A0887C94C00AC849E /* SOGoAptMailDeletion */,
);
name = "Mail Components";
sourceTree = "<group>";
name = Contacts;
sourceTree = "<group>";
};
+ ADB741FF0887C90200AC849E /* SOGoAptMailRemoval */ = {
+ isa = PBXGroup;
+ children = (
+ ADB742000887C90200AC849E /* SOGoAptMailRemoval.m */,
+ ADB742040887C93100AC849E /* SOGoAptMailRemoval.wo */,
+ );
+ name = SOGoAptMailRemoval;
+ sourceTree = "<group>";
+ };
+ ADB7420A0887C94C00AC849E /* SOGoAptMailDeletion */ = {
+ isa = PBXGroup;
+ children = (
+ ADB7420B0887C94C00AC849E /* SOGoAptMailDeletion.m */,
+ ADB7420C0887C95A00AC849E /* SOGoAptMailDeletion.wo */,
+ );
+ name = SOGoAptMailDeletion;
+ sourceTree = "<group>";
+ };
ADDF4B3006DCEAC800C4E7F8 /* Contacts */ = {
isa = PBXGroup;
children = (
+2005-07-15 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * v0.9.47
+
+ * SOGoAptMailDeletion.[wo,m]: new template being used when appointment
+ is deleted
+
+ * SOGoAptMailRemoval.[wo,m]: new template being used when attendee is
+ removed from appointment
+
+ * SOGoAppointmentObject.m: now sends emails for removal of attendees
+ and deletion of appointment
+
2005-07-15 Helge Hess <helge.hess@opengroupware.org>
* SOGoAppointmentFolder.m: fixed Cocoa warnings (v0.9.46)
SOGoAptMailNotification.m \
SOGoAptMailInvitation.m \
SOGoAptMailUpdate.m \
+ SOGoAptMailRemoval.m \
+ SOGoAptMailDeletion.m \
Appointments_RESOURCE_FILES += \
Version \
Appointments_COMPONENTS += \
SOGoAptMailInvitation.wo \
SOGoAptMailUpdate.wo \
+ SOGoAptMailRemoval.wo \
+ SOGoAptMailDeletion.wo \
-include GNUmakefile.preamble
include $(GNUSTEP_MAKEFILES)/wobundle.make
- (void)sendAppointmentUpdateEMailForOldAppointment:(SOGoAppointment *)_oldApt
newAppointment:(SOGoAppointment *)_newApt
toAttendees:(NSArray *)_attendees;
-- (void)sendRemovalEMailForAppointment:(SOGoAppointment *)_apt
+- (void)sendAttendeeRemovalEMailForAppointment:(SOGoAppointment *)_apt
+ toAttendees:(NSArray *)_attendees;
+- (void)sendAppointmentDeletionEMailForAppointment:(SOGoAppointment *)_apt
toAttendees:(NSArray *)_attendees;
@end
NSArray *uids, *props;
NSMutableArray *attendees, *storeUIDs, *removedUIDs;
NSException *storeError, *delError;
- BOOL didChangeAppointmentTime;
+ BOOL updateForcesReconsider;
- didChangeAppointmentTime = NO;
+ updateForcesReconsider = NO;
if ([_iCal length] == 0) {
return [NSException exceptionWithHTTPStatus:400 /* Bad Request */
storeUIDs = [NSMutableArray arrayWithArray:uids];
props = [changes updatedProperties];
+ /* detect whether sequence has to be increased */
+ if ([changes hasChanges])
+ [newApt increaseSequence];
+
/* preserve organizer */
organizer = [[newApt event] organizer];
[p setParticipationStatus:iCalPersonPartStatNeedsAction];
}
_iCal = [newApt iCalString];
- didChangeAppointmentTime = YES;
+ updateForcesReconsider = YES;
}
/* perform storing */
[self sendInvitationEMailForAppointment:newApt
toAttendees:attendees];
- if (didChangeAppointmentTime) {
+ if (updateForcesReconsider) {
attendees = [NSMutableArray arrayWithArray:[[newApt event] attendees]];
[attendees removeObjectsInArray:[changes insertedAttendees]];
[attendees removePerson:organizer];
attendees = [NSMutableArray arrayWithArray:[changes deletedAttendees]];
[attendees removePerson:organizer];
- [self sendRemovalEMailForAppointment:newApt
- toAttendees:attendees];
-
+ if ([attendees count]) {
+ SOGoAppointment *canceledApt;
+
+ canceledApt = [newApt copy];
+ [canceledApt cancelWithoutIncreasingSequence];
+ [self sendAttendeeRemovalEMailForAppointment:canceledApt
+ toAttendees:attendees];
+ [canceledApt release];
+ }
return nil;
}
SOGoAppointment *apt;
NSString *econtent;
NSArray *removedUIDs;
-
+ NSMutableArray *attendees;
+
/* load existing content */
econtent = [self iCalString]; /* if nil, this is a new appointment */
}
removedUIDs = [self attendeeUIDsFromAppointment:apt];
+
+ /* send notification email to attendees excluding organizer */
+ attendees = [NSMutableArray arrayWithArray:[[apt event] attendees]];
+ [attendees removePerson:[apt organizer]];
+ /* flag appointment as being canceled */
+ [apt cancelAndIncreaseSequence];
+ /* remove all attendees to signal complete removal */
+ [apt removeAllAttendees];
+
+ /* send notification email */
+ [self sendAppointmentDeletionEMailForAppointment:apt
+ toAttendees:attendees];
+
/* perform */
return [self deleteInUIDs:removedUIDs];
iCalPerson *attendee;
NSString *recipient;
SOGoAptMailNotification *p;
- NSString *subject, *text;
+ NSString *subject, *text, *header;
NGMutableHashMap *headerMap;
NGMimeMessage *msg;
NGMimeBodyPart *bodyPart;
[body addBodyPart:bodyPart];
/* calendar part */
+ header = [NSString stringWithFormat:@"text/calendar; method=%@;"
+ @" charset=utf-8",
+ [_newApt method]];
headerMap = [NGMutableHashMap hashMapWithCapacity:1];
- [headerMap setObject:@"text/calendar; charset=utf-8" forKey:@"content-type"];
+ [headerMap setObject:header forKey:@"content-type"];
bodyPart = [NGMimeBodyPart bodyPartWithHeader:headerMap];
[bodyPart setBody:[iCalString dataUsingEncoding:NSUTF8StringEncoding]];
toAttendees:_attendees];
}
-- (void)sendRemovalEMailForAppointment:(SOGoAppointment *)_apt
+- (void)sendAttendeeRemovalEMailForAppointment:(SOGoAppointment *)_apt
toAttendees:(NSArray *)_attendees
{
if (![_attendees count]) return;
+
+ [self sendEMailUsingTemplateNamed:@"Removal"
+ forOldAppointment:nil
+ andNewAppointment:_apt
+ toAttendees:_attendees];
+}
+
+- (void)sendAppointmentDeletionEMailForAppointment:(SOGoAppointment *)_apt
+ toAttendees:(NSArray *)_attendees
+{
+ if (![_attendees count]) return;
+
+ [self sendEMailUsingTemplateNamed:@"Deletion"
+ forOldAppointment:nil
+ andNewAppointment:_apt
+ toAttendees:_attendees];
}
@end /* SOGoAppointmentObject */
--- /dev/null
+/*
+ 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 SOGoAptMailDeletion : SOGoAptMailNotification
+{
+
+}
+
+@end
+
+@implementation SOGoAptMailDeletion
+
+@end
--- /dev/null
+<#IsSubject>Appointment <#AptStartDate /> at <#AptStartTime /> has been canceled</#IsSubject>
+<#IsBody>
+The appointment at <#AptStartDate /> <#AptStartTime /> has been cancelled by <#Organizer />.
+</#IsBody>
\ No newline at end of file
--- /dev/null
+AptStartDate: WOString {
+ value = newStartDate;
+ dateformat = "%d/%m/%y";
+ escapeHTML = NO;
+}
+
+AptStartTime: WOString {
+ value = newStartDate;
+ dateformat = "%H:%M";
+ escapeHTML = NO;
+}
+
+Organizer: WOString {
+ value = newApt.organizer.cnWithoutQuotes;
+ escapeHTML = NO;
+}
+
+HasHomePageURL: WOConditional {
+ condition = homePageURL.length;
+}
+
+HomePageURL: WOString {
+ value = appointmentURL;
+ escapeHTML = NO;
+}
+
+IsSubject: WOConditional {
+ condition = isSubject;
+}
+
+IsBody: WOConditional {
+ condition = isSubject;
+ negate = YES;
+}
--- /dev/null
+/*
+ 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 SOGoAptMailRemoval : SOGoAptMailNotification
+{
+
+}
+
+@end
+
+@implementation SOGoAptMailRemoval
+
+@end
--- /dev/null
+<#IsSubject>Removed from appointment <#AptStartDate /> at <#AptStartTime /></#IsSubject>
+<#IsBody>
+You have been removed by <#Organizer /> from the appointment scheduled at <#AptStartDate /> <#AptStartTime />.
+</#IsBody>
\ No newline at end of file
--- /dev/null
+AptStartDate: WOString {
+ value = newStartDate;
+ dateformat = "%d/%m/%y";
+ escapeHTML = NO;
+}
+
+AptStartTime: WOString {
+ value = newStartDate;
+ dateformat = "%H:%M";
+ escapeHTML = NO;
+}
+
+Organizer: WOString {
+ value = newApt.organizer.cnWithoutQuotes;
+ escapeHTML = NO;
+}
+
+HasHomePageURL: WOConditional {
+ condition = homePageURL.length;
+}
+
+HomePageURL: WOString {
+ value = appointmentURL;
+ escapeHTML = NO;
+}
+
+IsSubject: WOConditional {
+ condition = isSubject;
+}
+
+IsBody: WOConditional {
+ condition = isSubject;
+ negate = YES;
+}
# Version file
-SUBMINOR_VERSION:=46
+SUBMINOR_VERSION:=47
# v0.9.42 requires libSOGo v0.9.54
# v0.9.32 requires libGDLContentStore v4.5.26
+2005-07-14 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * v0.9.63
+
+ * SOGoAppointment.[hm]: new API to cancel appointments, NSCopying
+ support
+
2005-07-15 Helge Hess <helge.hess@opengroupware.org>
* v0.9.62
@class NSString, NSArray, NSCalendarDate, NGCalendarDateRange;
@class iCalPerson, iCalEvent, iCalRecurrenceRule;
-@interface SOGoAppointment : NSObject
+@interface SOGoAppointment : NSObject <NSCopying>
{
id calendar;
iCalEvent *event;
- (iCalPerson *)findParticipantWithEmail:(id)_email;
+/* actions */
+
+- (void)increaseSequence;
+- (void)cancelWithoutIncreasingSequence;
+- (void)cancelAndIncreaseSequence;
+
@end
#endif /* __SOGoAppointment_H_ */
}
- (void)dealloc {
- [self->calendar release];
- [self->event release];
+ [self->calendar release];
+ [self->event release];
+ [self->participants release];
[super dealloc];
}
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+ SOGoAppointment *new;
+
+ new = [[[self class] allocWithZone:_zone] init];
+
+ new->calendar = [self->calendar copyWithZone:_zone];
+ new->event = [self->event copyWithZone:_zone];
+ new->participants = [self->participants copyWithZone:_zone];
+
+ return new;
+}
+
/* accessors */
- (id)calendar {
- (NSString *)iCalString {
return [[SOGoAppointmentICalRenderer sharedAppointmentRenderer]
- stringForAppointment:self];
+ stringForAppointment:self];
}
- (NSString *)vEventString {
return [[SOGoAppointmentICalRenderer sharedAppointmentRenderer]
- vEventStringForAppointment:self];
+ vEventStringForAppointment:self];
}
/* forwarded methods */
- (BOOL)isParticipant:(id)_email {
NSArray *partEmails;
+ _email = [_email lowercaseString];
partEmails = [[self participants] valueForKey:@"rfc822Email"];
+ partEmails = [partEmails valueForKey:@"lowercaseString"];
return [partEmails containsObject:_email];
}
NSArray *ps;
unsigned i, count;
- ps = [self participants];
- count = [ps count];
+ _email = [_email lowercaseString];
+ ps = [self participants];
+ count = [ps count];
for (i = 0; i < count; i++) {
iCalPerson *p;
p = [ps objectAtIndex:i];
- if ([[p rfc822Email] isEqualToString:_email])
+ if ([[[p rfc822Email] lowercaseString] isEqualToString:_email])
return p;
}
return nil; /* not found */
return [self->event recurrenceRangesWithinCalendarDateRange:_r];
}
+/* actions */
+
+- (void)increaseSequence {
+ [self->event increaseSequence];
+}
+
+- (void)cancelWithoutIncreasingSequence {
+ [self setMethod:@"CANCEL"];
+}
+- (void)cancelAndIncreaseSequence {
+ [self cancelWithoutIncreasingSequence];
+ [self increaseSequence];
+}
/* description */
# version file
-SUBMINOR_VERSION:=62
+SUBMINOR_VERSION:=63
+# v0.9.63 requires libNGiCal v4.5.54
# v0.9.60 requires libNGiCal v4.5.49
# v0.9.50 requires libGDLContentStore v4.5.30
# v0.9.34 requires libGDLContentStore v4.5.26