]> err.no Git - scalable-opengroupware.org/blob - SOGo/UI/Scheduler/UIxAppointmentEditor.m
newAction for SOGo
[scalable-opengroupware.org] / SOGo / UI / Scheduler / UIxAppointmentEditor.m
1 /*
2   Copyright (C) 2000-2004 SKYRIX Software AG
3
4   This file is part of OpenGroupware.org.
5
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
9   later version.
10
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.
15
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
19   02111-1307, USA.
20 */
21 // $Id$
22
23
24 #include "common.h"
25 #include <SOGoUI/UIxComponent.h>
26 #include <SOGoLogic/SOGoAppointment.h>
27 #include <NGiCal/NGiCal.h>
28
29
30 /* TODO: CLEAN THIS MESS UP */
31
32 @interface NSDate(UsedPrivates)
33 - (NSString *)icalString; // TODO: this is in NGiCal
34 @end
35
36 @interface NSObject (AppointmentHack)
37 - (BOOL)isAppointment;
38 @end
39
40 @implementation NSObject (AppointmentHack)
41 - (BOOL)isAppointment {
42   return [self isKindOfClass:NSClassFromString(@"SOGoAppointmentObject")];
43 }
44 @end
45
46 @interface iCalPerson (Convenience)
47 - (NSString *)rfc822Email;
48 @end
49
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];
56     }
57     return _email;
58 }
59 @end
60
61 @interface UIxAppointmentEditor : UIxComponent
62 {
63     id appointment;
64     id participants;
65 }
66
67 - (SOGoAppointment *)appointment;
68 - (NSString *)iCalStringTemplate;
69 - (NSString *)iCalString;
70 - (BOOL)isNewAppointment;
71
72 @end
73
74 @implementation UIxAppointmentEditor
75
76 - (void)dealloc {
77     [self->appointment release];
78     [self->participants release];
79     [super dealloc];
80 }
81
82
83 /* accessors */
84
85
86 - (NSString *)formattedAptStartTime {
87     NSCalendarDate *date;
88     
89     date = [[self appointment] startDate];
90     /* TODO: convert this into display timeZone! */
91     return [date descriptionWithCalendarFormat:@"%A, %Y-%m-%d %H:%M %Z"];
92 }
93
94 - (BOOL)isNewAppointment {
95     return ! [[self clientObject] isAppointment];
96 }
97
98 - (NSString *)iCalString {
99     if([self isNewAppointment]) {
100         return [self iCalStringTemplate];
101     }
102     else {
103         return [[self clientObject] valueForKey:@"iCalString"];
104     }
105 }
106
107 - (NSString *)iCalStringTemplate {
108     static NSString *iCalStringTemplate = \
109     @"BEGIN:VCALENDAR\nMETHOD:REQUEST\nPRODID:OpenGroupware.org SOGo 0.9\n" \
110     @"VERSION:2.0\nBEGIN:VEVENT\nCLASS:PRIVATE\nSTATUS:CONFIRMED\n" \
111     @"DTSTART:%@\nDTEND:%@\n" \
112     @"TRANSP:OPAQUE\n" \
113     @"END:VEVENT\nEND:VCALENDAR";
114     NSCalendarDate *startDate, *endDate;
115     NSString *template;
116     
117     startDate = [self selectedDate];
118     endDate = [startDate dateByAddingYears:0 months:0 days:0
119                          hours:1 minutes:0 seconds:0];
120     
121     template = [NSString stringWithFormat:iCalStringTemplate,
122                            [startDate icalString],
123                            [endDate icalString]];
124     
125     return template;
126 }
127
128
129 /* backend */
130
131
132 - (SOGoAppointment *)appointment {
133     if(self->appointment == nil) {
134         self->appointment = [[SOGoAppointment alloc]
135           initWithICalString:[self iCalString]];
136     }
137     return self->appointment;
138 }
139
140 - (id)participants {
141     if(self->participants == nil) {
142         NSArray *attendees;
143         NSMutableArray *emailAddresses;
144         unsigned i, count;
145
146         attendees = [self->appointment attendees];
147         count = [attendees count];
148         emailAddresses = [[NSMutableArray alloc] initWithCapacity:count];
149         for(i = 0; i < count; i++) {
150             NSString *email;
151             
152             email = [[attendees objectAtIndex:i] rfc822Email];
153             if(email)
154                 [emailAddresses addObject:email];
155         }
156         self->participants = [[emailAddresses componentsJoinedByString:@"\n"]
157             retain];
158         [emailAddresses release];
159     }
160     return self->participants;
161 }
162
163
164 /* helper */
165
166 - (NSString *)uriAsFormat {
167     NSString *uri, *qp;
168     NSRange r;
169
170     uri = [[[self context] request] uri];
171     
172     /* first: identify query parameters */
173     r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
174     if (r.length > 0) {
175         uri = [uri substringToIndex:r.location];
176         qp = [uri substringFromIndex:r.location];
177     }
178     else {
179         qp = nil;
180     }
181     
182     /* next: strip trailing slash */
183     if([uri hasSuffix:@"/"])
184         uri = [uri substringToIndex:([uri length] - 1)];
185     r = [uri rangeOfString:@"/" options:NSBackwardsSearch];
186     
187     /* then: cut of last path component */
188     if(r.location == NSNotFound) { // no slash? are we at root?
189         uri = @"/";
190     }
191     else {
192         uri = [uri substringToIndex:(r.location + 1)];
193     }
194     /* next: append format token */
195     uri = [uri stringByAppendingString:@"%@"];
196     if(qp != nil)
197         uri = [uri stringByAppendingString:qp];
198     return uri;
199 }
200
201
202 /* new */
203
204
205 - (id)newAction {
206   WORequest *req;
207   WOResponse *r;
208   NSString *uri, *uriFormat, *objectId, *nextMethod;
209   
210   /* clientObject *is* SOGoAppointmentFolder, so this should be an instance method? */
211   objectId = [NSClassFromString(@"SOGoAppointmentFolder")
212     globallyUniqueObjectId];
213   
214   nextMethod = [NSString stringWithFormat:@"%@/edit", objectId];
215   uriFormat = [self uriAsFormat];
216   uri = [NSString stringWithFormat:uriFormat, nextMethod];
217
218   req = [[self context] request];
219   r = [WOResponse responseWithRequest:req];
220   [r setStatus:302 /* moved */];
221   [r setHeader:uri forKey:@"location"];
222   return r;
223 }
224
225
226 /* save */
227
228
229 - (id)saveAction {
230     SOGoAppointment *apt;
231     NSString *iCalString, *summary, *location, *nextMethod, *uri, *uriFormat;
232     NSCalendarDate *sd, *ed;
233     NSArray *ps;
234     unsigned i, count;
235     WOResponse *r;
236     WORequest *req;
237
238     req = [[self context] request];
239
240     /* get iCalString from hidden input */
241     iCalString = [req formValueForKey:@"ical"];
242     apt = [[SOGoAppointment alloc] initWithICalString:iCalString];
243
244     /* merge in form values */
245     sd = [NSCalendarDate dateWithString:[req formValueForKey:@"startDate"]
246                          calendarFormat:@"%Y-%m-%d %H:%M"];
247     [apt setStartDate:sd];
248     ed = [NSCalendarDate dateWithString:[req formValueForKey:@"endDate"]
249                          calendarFormat:@"%Y-%m-%d %H:%M"];
250     [apt setEndDate:ed];
251     summary = [req formValueForKey:@"summary"];
252     [apt setSummary:summary];
253     location = [req formValueForKey:@"location"];
254     [apt setLocation:location];
255
256     [apt removeAllAttendees]; /* clean up */
257     ps = [[req formValueForKey:@"participants"]
258         componentsSeparatedByString:@"\n"];
259     count = [ps count];
260     for(i = 0; i < count; i++) {
261         NSString *email;
262         
263         email = [ps objectAtIndex:i];
264         if([email length] > 0) {
265             iCalPerson *p;
266             NSRange cnr;
267
268             p = [[iCalPerson alloc] init];
269             [p setEmail:[NSString stringWithFormat:@"mailto:%@", email]];
270             /* construct a fake CN */
271             cnr = [email rangeOfString:@"@"];
272             if(cnr.location != NSNotFound) {
273                 [p setCn:[email substringToIndex:cnr.location]];
274             }
275             [apt addToAttendees:p];
276             [p release];
277         }
278     }
279
280     /* receive current representation for save operation */
281     iCalString = [apt iCalString];
282     [apt release];
283     
284
285     /* determine what's to do and where to go next */
286     if([self isNewAppointment]) {
287         nextMethod = @"duhduh";
288     }
289     else {
290         nextMethod = @"view";
291     }
292
293     NSLog(@"%s new iCalString:\n%@", __PRETTY_FUNCTION__, iCalString);
294
295     uriFormat = [self uriAsFormat];
296     uri = [NSString stringWithFormat:uriFormat, nextMethod];
297
298     r = [WOResponse responseWithRequest:req];
299     [r setStatus:302 /* moved */];
300     [r setHeader:uri forKey:@"location"];
301     return r;
302 }
303
304 @end