]> err.no Git - scalable-opengroupware.org/blob - UI/Scheduler/UIxComponentEditor.m
git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1172 d1b88da0-ebda-0310...
[scalable-opengroupware.org] / UI / Scheduler / UIxComponentEditor.m
1 /* UIxComponentEditor.m - this file is part of SOGo
2  *
3  * Copyright (C) 2006 Inverse groupe conseil
4  *
5  * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
6  *
7  * This file is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  *
12  * This file is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #import <Foundation/NSArray.h>
24 #import <Foundation/NSBundle.h>
25 #import <Foundation/NSException.h>
26 #import <Foundation/NSCalendarDate.h>
27 #import <Foundation/NSKeyValueCoding.h>
28 #import <Foundation/NSString.h>
29 #import <Foundation/NSUserDefaults.h>
30 #import <Foundation/NSURL.h>
31
32 #import <NGCards/iCalPerson.h>
33 #import <NGCards/iCalRepeatableEntityObject.h>
34 #import <NGCards/iCalRecurrenceRule.h>
35 #import <NGCards/NSString+NGCards.h>
36 #import <NGCards/NSCalendarDate+NGCards.h>
37 #import <NGObjWeb/SoSecurityManager.h>
38 #import <NGObjWeb/NSException+HTTP.h>
39 #import <NGObjWeb/WORequest.h>
40 #import <NGExtensions/NSCalendarDate+misc.h>
41 #import <NGExtensions/NSObject+Logs.h>
42 #import <NGExtensions/NSString+misc.h>
43
44 #import <SoObjects/Appointments/SOGoAppointmentFolder.h>
45 #import <SoObjects/Appointments/SOGoAppointmentObject.h>
46 #import <SoObjects/Appointments/SOGoTaskObject.h>
47 #import <SoObjects/SOGo/NSString+Utilities.h>
48 #import <SoObjects/SOGo/SOGoUser.h>
49 #import <SoObjects/SOGo/SOGoPermissions.h>
50
51 #import "UIxComponent+Scheduler.h"
52
53 #import "UIxComponentEditor.h"
54
55 @implementation UIxComponentEditor
56
57 - (id) init
58 {
59   if ((self = [super init]))
60     {
61       component = nil;
62       [self setPrivacy: @"PUBLIC"];
63       [self setIsCycleEndNever];
64       componentOwner = @"";
65       organizer = nil;
66       attendeesNames = nil;
67       attendeesEmails = nil;
68       calendarList = nil;
69     }
70
71   return self;
72 }
73
74 - (void) dealloc
75 {
76   [item release];
77   [cycleUntilDate release];
78   [title release];
79   [location release];
80   [organizer release];
81   [comment release];
82   [priority release];
83   [categories release];
84   [cycle release];
85   [cycleEnd release];
86   [url release];
87   [attendeesNames release];
88   [attendeesEmails release];
89   [calendarList release];
90
91   [super dealloc];
92 }
93
94 - (void) _loadAttendees
95 {
96   NSEnumerator *attendees;
97   iCalPerson *currentAttendee;
98   NSMutableString *names, *emails;
99
100   names = [NSMutableString new];
101   emails = [NSMutableString new];
102
103   attendees = [[component attendees] objectEnumerator];
104   currentAttendee = [attendees nextObject];
105   while (currentAttendee)
106     {
107       [names appendFormat: @"%@,", [currentAttendee cn]];
108       [emails appendFormat: @"%@,", [currentAttendee rfc822Email]];
109       currentAttendee = [attendees nextObject];
110     }
111
112   if ([names length] > 0)
113     {
114       ASSIGN (attendeesNames, [names substringToIndex: [names length] - 1]);
115       ASSIGN (attendeesEmails,
116               [emails substringToIndex: [emails length] - 1]);
117     }
118
119   [names release];
120   [emails release];
121 }
122
123 - (void) _loadCategories
124 {
125   NSString *compCategories, *simpleCategory;
126
127   compCategories = [component categories];
128   if ([compCategories length] > 0)
129     {
130       simpleCategory = [[compCategories componentsSeparatedByString: @","]
131                          objectAtIndex: 0];
132       ASSIGN (category, [simpleCategory uppercaseString]);
133     }
134 }
135
136 /* warning: we use this method which will be triggered by the template system
137    when the page is instantiated, but we should find another and cleaner way of
138    doing this... for example, when the clientObject is set */
139 - (void) setComponent: (iCalRepeatableEntityObject *) newComponent
140 {
141 //   iCalRecurrenceRule *rrule;
142   SOGoObject *co;
143
144   if (!component)
145     {
146       component = newComponent;
147
148       co = [self clientObject];
149       componentOwner = [co ownerInContext: nil];
150
151       ASSIGN (title, [component summary]);
152       ASSIGN (location, [component location]);
153       ASSIGN (comment, [component comment]);
154       ASSIGN (url, [[component url] absoluteString]);
155       ASSIGN (privacy, [component accessClass]);
156       ASSIGN (priority, [component priority]);
157       ASSIGN (status, [component status]);
158       ASSIGN (categories, [[component categories] commaSeparatedValues]);
159       ASSIGN (organizer, [component organizer]);
160       [self _loadCategories];
161       [self _loadAttendees];
162     }
163 //   /* cycles */
164 //   if ([component isRecurrent])
165 //     {
166 //       rrule = [[component recurrenceRules] objectAtIndex: 0];
167 //       [self adjustCycleControlsForRRule: rrule];
168 //     }
169 }
170
171 - (void) setSaveURL: (NSString *) newSaveURL
172 {
173   saveURL = newSaveURL;
174 }
175
176 - (NSString *) saveURL
177 {
178   return saveURL;
179 }
180
181 /* accessors */
182
183 - (void) setItem: (id) _item
184 {
185   ASSIGN (item, _item);
186 }
187
188 - (id) item
189 {
190   return item;
191 }
192
193 - (NSString *) itemPriorityText
194 {
195   return [self labelForKey: [NSString stringWithFormat: @"prio_%@", item]];
196 }
197
198 - (NSString *) itemPrivacyText
199 {
200   NSString *tag;
201
202   tag = [[self clientObject] componentTag];
203
204   return [self labelForKey: [NSString stringWithFormat: @"%@_%@", item, tag]];
205 }
206
207 - (NSString *) itemStatusText
208 {
209   return [self labelForKey: [NSString stringWithFormat: @"status_%@", item]];
210 }
211
212 - (void) setTitle: (NSString *) _value
213 {
214   ASSIGN (title, _value);
215 }
216
217 - (NSString *) title
218 {
219   return title;
220 }
221
222 - (void) setUrl: (NSString *) _url
223 {
224   ASSIGN (url, _url);
225 }
226
227 - (NSString *) url
228 {
229   return url;
230 }
231
232 - (void) setAttendeesNames: (NSString *) newAttendeesNames
233 {
234   ASSIGN (attendeesNames, newAttendeesNames);
235 }
236
237 - (NSString *) attendeesNames
238 {
239   return attendeesNames;
240 }
241
242 - (void) setAttendeesEmails: (NSString *) newAttendeesEmails
243 {
244   ASSIGN (attendeesEmails, newAttendeesEmails);
245 }
246
247 - (NSString *) attendeesEmails
248 {
249   return attendeesEmails;
250 }
251
252 - (void) setLocation: (NSString *) _value
253 {
254   ASSIGN (location, _value);
255 }
256
257 - (NSString *) location
258 {
259   return location;
260 }
261
262 - (void) setComment: (NSString *) _value
263 {
264   ASSIGN (comment, _value);
265 }
266
267 - (NSString *) comment
268 {
269   return comment;
270 }
271
272 - (NSArray *) categoryList
273 {
274   static NSArray *categoryItems = nil;
275
276   if (!categoryItems)
277     {
278       categoryItems = [NSArray arrayWithObjects: @"ANNIVERSARY",
279                                @"BIRTHDAY",
280                                @"BUSINESS",
281                                @"CALLS", 
282                                @"CLIENTS",
283                                @"COMPETITION",
284                                @"CUSTOMER",
285                                @"FAVORITES",
286                                @"FOLLOW UP",
287                                @"GIFTS",
288                                @"HOLIDAYS",
289                                @"IDEAS",
290                                @"ISSUES",
291                                @"MISCELLANEOUS",
292                                @"PERSONAL",
293                                @"PROJECTS",
294                                @"PUBLIC HOLIDAY",
295                                @"STATUS",
296                                @"SUPPLIERS",
297                                @"TRAVEL",
298                                @"VACATION",
299                               nil];
300       [categoryItems retain];
301     }
302
303   return categoryItems;
304 }
305
306 - (void) setCategories: (NSArray *) _categories
307 {
308   ASSIGN (categories, _categories);
309 }
310
311 - (NSArray *) categories
312 {
313   return categories;
314 }
315
316 - (void) setCategory: (NSArray *) newCategory
317 {
318   ASSIGN (category, newCategory);
319 }
320
321 - (NSString *) category
322 {
323   return category;
324 }
325
326 - (NSString *) itemCategoryText
327 {
328   return [self labelForKey:
329                  [NSString stringWithFormat: @"category_%@", item]];
330 }
331
332 - (NSArray *) calendarList
333 {
334   SOGoAppointmentFolder *folder;
335   NSEnumerator *allCalendars;
336   NSDictionary *currentCalendar;
337
338   if (!calendarList)
339     {
340       calendarList = [NSMutableArray new];
341       folder = [[self clientObject] container];
342       allCalendars = [[folder calendarFolders] objectEnumerator];
343       currentCalendar = [allCalendars nextObject];
344       while (currentCalendar)
345         {
346           if ([[currentCalendar objectForKey: @"active"] boolValue])
347             [calendarList addObject: currentCalendar];
348           currentCalendar = [allCalendars nextObject];
349         }
350     }
351
352   return calendarList;
353 }
354
355 - (NSString *) calendarsFoldersList
356 {
357   NSArray *calendars;
358
359   calendars = [[self calendarList] valueForKey: @"folder"];
360
361   return [calendars componentsJoinedByString: @","];
362 }
363
364 - (NSString *) componentCalendar
365 {
366   return @"/";
367 }
368
369 /* priorities */
370
371 - (NSArray *) priorities
372 {
373   /* 0 == undefined
374      5 == normal
375      1 == high
376   */
377   static NSArray *priorities = nil;
378
379   if (!priorities)
380     {
381       priorities = [NSArray arrayWithObjects: @"0", @"5", @"1", nil];
382       [priorities retain];
383     }
384
385   return priorities;
386 }
387
388 - (void) setPriority: (NSString *) _priority
389 {
390   ASSIGN (priority, _priority);
391 }
392
393 - (NSString *) priority
394 {
395   return priority;
396 }
397
398 - (NSArray *) privacyClasses
399 {
400   static NSArray *priorities = nil;
401
402   if (!priorities)
403     {
404       priorities = [NSArray arrayWithObjects: @"PUBLIC",
405                             @"CONFIDENTIAL", @"PRIVATE", nil];
406       [priorities retain];
407     }
408
409   return priorities;
410 }
411
412 - (void) setPrivacy: (NSString *) _privacy
413 {
414   ASSIGN (privacy, _privacy);
415 }
416
417 - (NSString *) privacy
418 {
419   return privacy;
420 }
421
422 - (NSArray *) statusTypes
423 {
424   static NSArray *priorities = nil;
425
426   if (!priorities)
427     {
428       priorities = [NSArray arrayWithObjects: @"", @"TENTATIVE", @"CONFIRMED", @"CANCELLED", nil];
429       [priorities retain];
430     }
431
432   return priorities;
433 }
434
435 - (void) setStatus: (NSString *) _status
436 {
437   ASSIGN (status, _status);
438 }
439
440 - (NSString *) status
441 {
442   return status;
443 }
444
445 - (NSArray *) cycles
446 {
447   NSBundle *bundle;
448   NSString *path;
449   static NSArray *cycles = nil;
450   
451   if (!cycles)
452     {
453       bundle = [NSBundle bundleForClass:[self class]];
454       path   = [bundle pathForResource: @"cycles" ofType: @"plist"];
455       NSAssert(path != nil, @"Cannot find cycles.plist!");
456       cycles = [[NSArray arrayWithContentsOfFile:path] retain];
457       NSAssert(cycles != nil, @"Cannot instantiate cycles from cycles.plist!");
458     }
459
460   return cycles;
461 }
462
463 - (void) setCycle: (NSDictionary *) _cycle
464 {
465   ASSIGN (cycle, _cycle);
466 }
467
468 - (NSDictionary *) cycle
469 {
470   return cycle;
471 }
472
473 - (BOOL) hasCycle
474 {
475   return ([cycle objectForKey: @"rule"] != nil);
476 }
477
478 - (NSString *) cycleLabel
479 {
480   NSString *key;
481   
482   key = [(NSDictionary *)item objectForKey: @"label"];
483
484   return [self labelForKey:key];
485 }
486
487 - (void) setCycleUntilDate: (NSCalendarDate *) _cycleUntilDate
488 {
489 //   NSCalendarDate *until;
490
491 //   /* copy hour/minute/second from startDate */
492 //   until = [_cycleUntilDate hour: [startDate hourOfDay]
493 //                            minute: [startDate minuteOfHour]
494 //                            second: [startDate secondOfMinute]];
495 //   [until setTimeZone: [startDate timeZone]];
496 //   ASSIGN (cycleUntilDate, until);
497 }
498
499 - (NSCalendarDate *) cycleUntilDate
500 {
501   return cycleUntilDate;
502 }
503
504 - (iCalRecurrenceRule *) rrule
505 {
506   NSString *ruleRep;
507   iCalRecurrenceRule *rule;
508
509   if (![self hasCycle])
510     return nil;
511   ruleRep = [cycle objectForKey: @"rule"];
512   rule = [iCalRecurrenceRule recurrenceRuleWithICalRepresentation:ruleRep];
513
514   if (cycleUntilDate && [self isCycleEndUntil])
515     [rule setUntilDate:cycleUntilDate];
516
517   return rule;
518 }
519
520 - (void) adjustCycleControlsForRRule: (iCalRecurrenceRule *) _rrule
521 {
522 //   NSDictionary *c;
523 //   NSCalendarDate *until;
524   
525 //   c = [self cycleMatchingRRule:_rrule];
526 //   [self setCycle:c];
527
528 //   until = [[[_rrule untilDate] copy] autorelease];
529 //   if (!until)
530 //     until = startDate;
531 //   else
532 //     [self setIsCycleEndUntil];
533
534 //   [until setTimeZone:[[self clientObject] userTimeZone]];
535 //   [self setCycleUntilDate:until];
536 }
537
538 /*
539  This method is necessary, because we have a fixed sets of cycles in the UI.
540  The model is able to represent arbitrary rules, however.
541  There SHOULD be a different UI, similar to iCal.app, to allow modelling
542  of more complex rules.
543  
544  This method obviously cannot map all existing rules back to the fixed list
545  in cycles.plist. This should be fixed in a future version when interop
546  becomes more important.
547  */
548 - (NSDictionary *) cycleMatchingRRule: (iCalRecurrenceRule *) _rrule
549 {
550   NSString *cycleRep;
551   NSArray *cycles;
552   unsigned i, count;
553
554   if (!_rrule)
555     return [[self cycles] objectAtIndex:0];
556
557   cycleRep = [_rrule versitString];
558   cycles   = [self cycles];
559   count    = [cycles count];
560   for (i = 1; i < count; i++) {
561     NSDictionary *c;
562     NSString *cr;
563
564     c  = [cycles objectAtIndex:i];
565     cr = [c objectForKey: @"rule"];
566     if ([cr isEqualToString:cycleRep])
567       return c;
568   }
569   [self warnWithFormat: @"No default cycle for rrule found! -> %@", _rrule];
570   return nil;
571 }
572
573 /* cycle "ends" - supposed to be 'never', 'COUNT' or 'UNTIL' */
574 - (NSArray *) cycleEnds
575 {
576   static NSArray *ends = nil;
577   
578   if (!ends)
579     {
580       ends = [NSArray arrayWithObjects: @"cycle_end_never",
581                       @"cycle_end_until", nil];
582       [ends retain];
583     }
584
585   return ends;
586 }
587
588 - (void) setCycleEnd: (NSString *) _cycleEnd
589 {
590   ASSIGN (cycleEnd, _cycleEnd);
591 }
592
593 - (NSString *) cycleEnd
594 {
595   return cycleEnd;
596 }
597
598 - (BOOL) isCycleEndUntil
599 {
600   return (cycleEnd && [cycleEnd isEqualToString: @"cycle_end_until"]);
601 }
602
603 - (void) setIsCycleEndUntil
604 {
605   [self setCycleEnd: @"cycle_end_until"];
606 }
607
608 - (void) setIsCycleEndNever
609 {
610   [self setCycleEnd: @"cycle_end_never"];
611 }
612
613 /* helpers */
614 - (NSString *) completeURIForMethod: (NSString *) _method
615 {
616   NSString *uri;
617   NSRange r;
618     
619   uri = [[[self context] request] uri];
620     
621   /* first: identify query parameters */
622   r = [uri rangeOfString: @"?" options:NSBackwardsSearch];
623   if (r.length > 0)
624     uri = [uri substringToIndex:r.location];
625     
626   /* next: append trailing slash */
627   if (![uri hasSuffix: @"/"])
628     uri = [uri stringByAppendingString: @"/"];
629   
630   /* next: append method */
631   uri = [uri stringByAppendingString:_method];
632     
633   /* next: append query parameters */
634   return [self completeHrefForMethod:uri];
635 }
636
637 - (BOOL) isWriteableClientObject
638 {
639   return [[self clientObject] 
640                 respondsToSelector: @selector(saveContentString:)];
641 }
642
643 - (BOOL) containsConflict: (id) _component
644 {
645   [self subclassResponsibility: _cmd];
646
647   return NO;
648 }
649
650 /* access */
651
652 #if 0
653 - (iCalPerson *) getOrganizer
654 {
655   iCalPerson *p;
656   NSString *emailProp;
657   
658   emailProp = [@"MAILTO:" stringByAppendingString:[self emailForUser]];
659   p = [[[iCalPerson alloc] init] autorelease];
660   [p setEmail:emailProp];
661   [p setCn:[self cnForUser]];
662   return p;
663 }
664 #endif
665
666 - (BOOL) isMyComponent
667 {
668   return ([[context activeUser] hasEmail: [organizer rfc822Email]]);
669 }
670
671 - (BOOL) canEditComponent
672 {
673   return [self isMyComponent];
674 }
675
676 /* response generation */
677
678 - (NSString *) initialCycleVisibility
679 {
680   return ([self hasCycle]
681           ? @"visibility: visible;"
682           : @"visibility: hidden;");
683 }
684
685 - (NSString *) initialCycleEndUntilVisibility {
686   return ([self isCycleEndUntil]
687           ? @"visibility: visible;"
688           : @"visibility: hidden;");
689 }
690
691 // - (NSString *) iCalParticipantsAndResourcesStringFromQueryParameters
692 // {
693 //   NSString *s;
694   
695 //   s = [self iCalParticipantsStringFromQueryParameters];
696 //   return [s stringByAppendingString:
697 //               [self iCalResourcesStringFromQueryParameters]];
698 // }
699
700 // - (NSString *) iCalParticipantsStringFromQueryParameters
701 // {
702 //   static NSString *iCalParticipantString = @"ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;CN=\"%@\":MAILTO:%@\r\n";
703   
704 //   return [self iCalStringFromQueryParameter: @"ps"
705 //                format: iCalParticipantString];
706 // }
707
708 // - (NSString *) iCalResourcesStringFromQueryParameters
709 // {
710 //   static NSString *iCalResourceString = @"ATTENDEE;ROLE=NON-PARTICIPANT;CN=\"%@\":MAILTO:%@\r\n";
711
712 //   return [self iCalStringFromQueryParameter: @"rs"
713 //                format: iCalResourceString];
714 // }
715
716 // - (NSString *) iCalStringFromQueryParameter: (NSString *) _qp
717 //                                      format: (NSString *) _format
718 // {
719 //   AgenorUserManager *um;
720 //   NSMutableString *iCalRep;
721 //   NSString *s;
722
723 //   um = [AgenorUserManager sharedUserManager];
724 //   iCalRep = (NSMutableString *)[NSMutableString string];
725 //   s = [self queryParameterForKey:_qp];
726 //   if(s && [s length] > 0) {
727 //     NSArray *es;
728 //     unsigned i, count;
729     
730 //     es = [s componentsSeparatedByString: @","];
731 //     count = [es count];
732 //     for(i = 0; i < count; i++) {
733 //       NSString *email, *cn;
734       
735 //       email = [es objectAtIndex:i];
736 //       cn = [um getCNForUID:[um getUIDForEmail:email]];
737 //       [iCalRep appendFormat:_format, cn, email];
738 //     }
739 //   }
740 //   return iCalRep;
741 // }
742
743 - (NSException *) validateObjectForStatusChange
744 {
745   id co;
746
747   co = [self clientObject];
748   if (![co respondsToSelector: @selector(changeParticipationStatus:)])
749     return [NSException exceptionWithHTTPStatus: 400 /* Bad Request */
750                         reason:
751                           @"method cannot be invoked on the specified object"];
752
753   return nil;
754 }
755
756 /* contact editor compatibility */
757
758 - (NSString *) urlButtonClasses
759 {
760   NSString *classes;
761
762   if ([url length])
763     classes = @"button";
764   else
765     classes = @"button _disabled";
766
767   return classes;
768 }
769
770 - (void) _handleAttendeesEdition
771 {
772   NSArray *names, *emails;
773   NSMutableArray *newAttendees;
774   unsigned int count, max;
775   NSString *currentEmail;
776   iCalPerson *currentAttendee;
777
778   newAttendees = [NSMutableArray new];
779   if ([attendeesNames length] > 0)
780     {
781       names = [attendeesNames componentsSeparatedByString: @","];
782       emails = [attendeesEmails componentsSeparatedByString: @","];
783       max = [emails count];
784       for (count = 0; count < max; count++)
785         {
786           currentEmail = [emails objectAtIndex: count];
787           currentAttendee = [component findParticipantWithEmail: currentEmail];
788           if (!currentAttendee)
789             {
790               currentAttendee = [iCalPerson elementWithTag: @"attendee"];
791               [currentAttendee setCn: [names objectAtIndex: count]];
792               [currentAttendee setEmail: currentEmail];
793               [currentAttendee setRole: @"REQ-PARTICIPANT"];
794               [currentAttendee
795                 setParticipationStatus: iCalPersonPartStatNeedsAction];
796             }
797           [newAttendees addObject: currentAttendee];
798         }
799     }
800
801   [component setAttendees: newAttendees];
802   [newAttendees release];
803 }
804
805 - (void) _handleOrganizer
806 {
807   NSString *organizerEmail;
808   SOGoUser *activeUser;
809   NSDictionary *primaryIdentity;
810
811   organizerEmail = [[component organizer] email];
812   if ([organizerEmail length] == 0)
813     {
814       if ([[component attendees] count] > 0)
815         {
816           ASSIGN (organizer, [iCalPerson elementWithTag: @"organizer"]);
817           activeUser = [context activeUser];
818           primaryIdentity = [activeUser primaryIdentity];
819           [organizer setCn: [activeUser cn]];
820           [organizer setEmail: [primaryIdentity objectForKey: @"email"]];
821           [component setOrganizer: organizer];
822         }
823     }
824   else
825     {
826       if ([[component attendees] count] == 0)
827         {
828           ASSIGN (organizer, [iCalPerson elementWithTag: @"organizer"]);
829           [component setOrganizer: organizer];
830         }
831     }
832 }
833
834 - (void) takeValuesFromRequest: (WORequest *) _rq
835                      inContext: (WOContext *) _ctx
836 {
837   NSCalendarDate *now;
838   SOGoCalendarComponent *clientObject;
839
840   [super takeValuesFromRequest: _rq inContext: _ctx];
841
842   now = [NSCalendarDate calendarDate];
843   [component setSummary: title];
844   [component setLocation: location];
845   [component setComment: comment];
846   [component setUrl: url];
847   [component setAccessClass: privacy];
848   [component setCategories: [category capitalizedString]];
849   [self _handleAttendeesEdition];
850   [self _handleOrganizer];
851   clientObject = [self clientObject];
852   if ([clientObject isNew])
853     {
854       [component setUid: [clientObject nameInContainer]];
855       [component setCreated: now];
856       [component setTimeStampAsDate: now];
857       [component setPriority: @"0"];
858     }
859   [component setLastModified: now];
860 }
861
862 - (NSString *) toolbar
863 {
864   SOGoCalendarComponent *clientObject;
865   NSString *toolbarFilename;
866   iCalPerson *participant;
867   iCalPersonPartStat participationStatus;
868   SoSecurityManager *sm;
869   NSString *owner;
870
871   sm = [SoSecurityManager sharedSecurityManager];
872   clientObject = [self clientObject];
873
874   owner = [clientObject ownerInContext: context];
875   participant = [clientObject findParticipantWithUID: owner];
876
877   if (participant
878       && ![sm validatePermission: SOGoCalendarPerm_RespondToComponent
879               onObject: clientObject
880               inContext: context])
881     {
882       participationStatus = [participant participationStatus];
883       /* Lightning does not manage participation status within tasks */
884       if (participationStatus == iCalPersonPartStatAccepted)
885         toolbarFilename = @"SOGoAppointmentObjectDecline.toolbar";
886       else if (participationStatus == iCalPersonPartStatDeclined)
887         toolbarFilename = @"SOGoAppointmentObjectAccept.toolbar";
888       else
889         toolbarFilename = @"SOGoAppointmentObjectAcceptOrDecline.toolbar";
890     }
891   else if (![sm validatePermission: SOGoCalendarPerm_ModifyComponent
892                 onObject: clientObject
893                 inContext: context])
894     {
895       if ([[clientObject componentTag] isEqualToString: @"vevent"])
896         toolbarFilename = @"SOGoAppointmentObject.toolbar";
897       else
898         toolbarFilename = @"SOGoTaskObject.toolbar";
899     }
900   else
901     toolbarFilename = @"SOGoComponentClose.toolbar";
902
903   return toolbarFilename;
904 }
905
906 @end