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