2 Copyright (C) 2000-2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
25 #include <SOGoUI/UIxComponent.h>
26 #include <SOGoLogic/SOGoAppointment.h>
27 #include <NGiCal/NGiCal.h>
30 /* TODO: CLEAN THIS MESS UP */
32 @interface NSDate(UsedPrivates)
33 - (NSString *)icalString; // TODO: this is in NGiCal
36 @interface NSObject (AppointmentHack)
37 - (BOOL)isAppointment;
40 @implementation NSObject (AppointmentHack)
41 - (BOOL)isAppointment {
42 return [self isKindOfClass:NSClassFromString(@"SOGoAppointmentObject")];
46 @interface iCalPerson (Convenience)
47 - (NSString *)rfc822Email;
50 @implementation iCalPerson (Convenience)
51 - (NSString *)rfc822Email {
52 NSString *_email = [self email];
53 NSRange colon = [_email rangeOfString:@":"];
54 if(colon.location != NSNotFound) {
55 return [_email substringFromIndex:colon.location + 1];
61 @interface UIxAppointmentEditor : UIxComponent
67 - (SOGoAppointment *)appointment;
68 - (NSString *)iCalStringTemplate;
69 - (NSString *)iCalString;
73 @implementation UIxAppointmentEditor
76 [self->appointment release];
77 [self->participants release];
85 - (NSString *)formattedAptStartTime {
88 date = [[[[self appointment] startDate] copy] autorelease];
89 [date setTimeZone:[self viewTimeZone]];
90 return [date descriptionWithCalendarFormat:@"%A, %Y-%m-%d %H:%M %Z"];
93 - (BOOL)isNewAppointment {
94 /* that doesn't work! */
95 return ![[self clientObject] isAppointment];
98 - (NSString *)iCalString {
99 // TODO: improve check for new appointment
102 ical = [[self clientObject] valueForKey:@"iCalString"];
103 if ([ical length] == 0) /* a new appointment */
104 ical = [self iCalStringTemplate];
109 - (NSString *)iCalStringTemplate {
110 static NSString *iCalStringTemplate = \
111 @"BEGIN:VCALENDAR\nMETHOD:REQUEST\nPRODID:OpenGroupware.org SOGo 0.9\n"
116 @"STATUS:CONFIRMED\n"
124 NSCalendarDate *startDate, *endDate;
127 startDate = [self selectedDate];
128 endDate = [startDate dateByAddingYears:0 months:0 days:0
129 hours:1 minutes:0 seconds:0];
131 template = [NSString stringWithFormat:iCalStringTemplate,
132 [[self clientObject] nameInContainer],
133 [[NSCalendarDate date] icalString],
134 [startDate icalString],
135 [endDate icalString]];
143 - (SOGoAppointment *)appointment {
144 if(self->appointment == nil) {
145 self->appointment = [[SOGoAppointment alloc]
146 initWithICalString:[self iCalString]];
148 return self->appointment;
153 NSMutableArray *emailAddresses;
156 if (self->participants)
157 return self->participants;
159 attendees = [self->appointment attendees];
160 count = [attendees count];
161 emailAddresses = [[NSMutableArray alloc] initWithCapacity:count];
162 for (i = 0; i < count; i++) {
165 email = [[attendees objectAtIndex:i] rfc822Email];
167 [emailAddresses addObject:email];
171 [[emailAddresses componentsJoinedByString:@"\n"] copy];
172 [emailAddresses release];
173 return self->participants;
179 - (NSString *)uriAsFormat {
183 uri = [[[self context] request] uri];
185 /* first: identify query parameters */
186 r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
188 qp = [uri substringFromIndex:r.location];
189 uri = [uri substringToIndex:r.location];
194 /* next: strip trailing slash */
195 if ([uri hasSuffix:@"/"])
196 uri = [uri substringToIndex:([uri length] - 1)];
197 r = [uri rangeOfString:@"/" options:NSBackwardsSearch];
199 /* then: cut of last path component */
200 if (r.length == 0) // no slash? are we at root?
203 uri = [uri substringToIndex:(r.location + 1)];
205 /* next: append format token */
206 uri = [uri stringByAppendingString:@"%@"];
208 uri = [uri stringByAppendingString:qp];
218 This method creates a unique ID and redirects to the "edit" method on the
220 It is actually a folder method and should be defined on the folder.
222 Note: 'clientObject' is the SOGoAppointmentFolder!
226 NSString *uri, *uriFormat, *objectId, *nextMethod;
228 objectId = [NSClassFromString(@"SOGoAppointmentFolder")
229 globallyUniqueObjectId];
231 nextMethod = [NSString stringWithFormat:@"%@/edit", objectId];
232 uriFormat = [self uriAsFormat];
233 uri = [[NSString alloc] initWithFormat:uriFormat, nextMethod];
234 req = [[self context] request];
235 r = [WOResponse responseWithRequest:req];
236 [r setStatus:302 /* moved */];
237 [r setHeader:uri forKey:@"location"];
238 [uri release]; uri = nil;
245 /* returned dates are in GMT */
246 - (NSCalendarDate *)_dateFromString:(NSString *)_str {
247 NSCalendarDate *date;
249 date = [NSCalendarDate dateWithString:_str
250 calendarFormat:@"%Y-%m-%d %H:%M %Z"];
251 [date setTimeZone:[self backendTimeZone]];
256 SOGoAppointment *apt;
257 NSString *iCalString;
258 NSString *summary, *location, *uri, *uriFormat;
259 NSCalendarDate *sd, *ed;
265 req = [[self context] request];
267 /* get iCalString from hidden input */
269 iCalString = [req formValueForKey:@"ical"];
270 if ([iCalString length] == 0) {
271 // TODO: improve user experience ... (eg error panel like Zope)
272 return [NSException exceptionWithHTTPStatus:400 /* bad request */
273 reason:@"missing iCalendar form data in request"];
276 apt = [[SOGoAppointment alloc] initWithICalString:iCalString];
278 /* merge in form values */
280 sd = [self _dateFromString:[req formValueForKey:@"startDate"]];
281 ed = [self _dateFromString:[req formValueForKey:@"endDate"]];
282 [apt setStartDate:sd];
285 summary = [req formValueForKey:@"summary"];
286 [apt setSummary:summary];
287 location = [req formValueForKey:@"location"];
288 [apt setLocation:location];
290 [apt removeAllAttendees]; /* clean up */
291 ps = [[req formValueForKey:@"participants"]
292 componentsSeparatedByString:@"\n"];
294 for (i = 0; i < count; i++) {
299 email = [ps objectAtIndex:i];
300 if ([email length] == 0)
303 p = [[iCalPerson alloc] init];
304 [p setEmail:[@"mailto:" stringByAppendingString:[email stringValue]]];
305 /* construct a fake CN */
306 cnr = [email rangeOfString:@"@"];
308 [p setCn:[email substringToIndex:cnr.location]];
309 [apt addToAttendees:p];
313 /* receive current representation for save operation */
314 iCalString = [apt iCalString];
315 [apt release]; apt = nil;
318 NSLog(@"%s new iCalString:\n%@", __PRETTY_FUNCTION__, iCalString);
323 ex = [[self clientObject] saveContentString:iCalString];
325 // TODO: add some error handling in form! (eg like in Zope)
329 uriFormat = [self uriAsFormat];
330 uri = [NSString stringWithFormat:uriFormat, @"view"];
332 r = [WOResponse responseWithRequest:req];
333 [r setStatus:302 /* moved */];
334 [r setHeader:uri forKey:@"location"];
338 @end /* UIxAppointmentEditor */