]> err.no Git - scalable-opengroupware.org/blob - SoObjects/Appointments/SOGoCalendarComponent.m
git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1031 d1b88da0-ebda-0310...
[scalable-opengroupware.org] / SoObjects / Appointments / SOGoCalendarComponent.m
1 /* SOGoCalendarComponent.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/NSString.h>
24
25 #import <NGCards/iCalCalendar.h>
26 #import <NGCards/iCalPerson.h>
27 #import <NGCards/iCalRepeatableEntityObject.h>
28 #import <NGMime/NGMime.h>
29 #import <NGMail/NGMail.h>
30 #import <NGMail/NGSendMail.h>
31
32 #import <SOGo/AgenorUserManager.h>
33 #import <SOGo/SOGoPermissions.h>
34 #import <SOGo/SOGoUser.h>
35
36 #import "common.h"
37
38 #import "SOGoAptMailNotification.h"
39 #import "SOGoCalendarComponent.h"
40
41 static NSString *mailTemplateDefaultLanguage = nil;
42 static BOOL sendEMailNotifications = NO;
43
44 @implementation SOGoCalendarComponent
45
46 + (void) initialize
47 {
48   NSUserDefaults      *ud;
49   static BOOL         didInit = NO;
50   
51   if (!didInit)
52     {
53       didInit = YES;
54   
55       ud = [NSUserDefaults standardUserDefaults];
56       mailTemplateDefaultLanguage = [[ud stringForKey:@"SOGoDefaultLanguage"]
57                                       retain];
58       if (!mailTemplateDefaultLanguage)
59         mailTemplateDefaultLanguage = @"French";
60
61       sendEMailNotifications
62         = [ud boolForKey: @"SOGoAppointmentSendEMailNotifications"];
63     }
64 }
65
66 - (id) init
67 {
68   if ((self = [super init]))
69     {
70       calendar = nil;
71       calContent = nil;
72     }
73
74   return self;
75 }
76
77 - (void) dealloc
78 {
79   if (calendar)
80     [calendar release];
81   if (calContent)
82     [calContent release];
83   [super dealloc];
84 }
85
86 - (NSString *) davContentType
87 {
88   return @"text/calendar";
89 }
90
91 - (NSString *) componentTag
92 {
93   [self subclassResponsibility: _cmd];
94
95   return nil;
96 }
97
98 - (void) _filterPrivateComponent: (iCalEntityObject *) component
99 {
100   [component setSummary: @""];
101   [component setComment: @""];
102   [component setUserComment: @""];
103   [component setLocation: @""];
104   [component setCategories: @""];
105   [component setUrl: @""];
106   [component removeAllAttendees];
107   [component removeAllAlarms];
108 }
109
110 - (NSString *) contentAsString
111 {
112   NSString *tmpContent, *email;
113   iCalCalendar *tmpCalendar;
114   iCalRepeatableEntityObject *tmpComponent;
115   WOContext *context;
116
117   if (!calContent)
118     {
119       tmpContent = [super contentAsString];
120       calContent = tmpContent;
121       if ([tmpContent length] > 0)
122         {
123           tmpCalendar = [iCalCalendar parseSingleFromSource: tmpContent];
124           tmpComponent = (iCalRepeatableEntityObject *) [tmpCalendar firstChildWithTag: [self componentTag]];
125           if (![tmpComponent isPublic])
126             {
127               context = [[WOApplication application] context];
128               email = [[context activeUser] email];
129               if (!([tmpComponent isOrganizer: email]
130                     || [tmpComponent isParticipant: email]))
131                 {
132                   //             content = tmpContent;
133                   [self _filterPrivateComponent: tmpComponent];
134                   calContent = [tmpCalendar versitString];
135                 }
136             }
137         }
138
139       [calContent retain];
140     }
141
142   return calContent;
143 }
144
145 - (NSException *) saveContentString: (NSString *) contentString
146                         baseVersion: (unsigned int) baseVersion
147 {
148   NSException *result;
149
150   result = [super saveContentString: contentString
151                   baseVersion: baseVersion];
152   if (!result && calContent)
153     {
154       [calContent release];
155       calContent = nil;
156     }
157
158   return result;
159 }
160
161 - (iCalCalendar *) calendar
162 {
163   NSString *iCalString;
164
165   if (!calendar)
166     {
167       iCalString = [self contentAsString];
168       if (iCalString)
169         {
170           calendar = [iCalCalendar parseSingleFromSource: iCalString];
171           [calendar retain];
172         }
173     }
174
175   return calendar;
176 }
177
178 - (iCalRepeatableEntityObject *) component
179 {
180   return (iCalRepeatableEntityObject *)
181     [[self calendar]
182       firstChildWithTag: [self componentTag]];
183 }
184
185 /* raw saving */
186
187 - (NSException *) primarySaveContentString: (NSString *) _iCalString
188 {
189   return [super saveContentString: _iCalString];
190 }
191
192 - (NSException *) primaryDelete
193 {
194   return [super delete];
195 }
196
197 - (NSException *) deleteWithBaseSequence: (int) a
198 {
199   [self subclassResponsibility: _cmd];
200
201   return nil;
202 }
203
204 - (NSException *) delete
205 {
206   return [self deleteWithBaseSequence:0];
207 }
208
209 /* EMail Notifications */
210 - (NSString *) homePageURLForPerson: (iCalPerson *) _person
211 {
212   NSString *baseURL;
213   NSString *uid;
214   WOContext *ctx;
215   NSArray *traversalObjects;
216
217   /* generate URL from traversal stack */
218   ctx = [[WOApplication application] context];
219   traversalObjects = [ctx objectTraversalStack];
220   if ([traversalObjects count] > 0)
221     baseURL = [[traversalObjects objectAtIndex:0] baseURLInContext:ctx];
222   else
223     {
224       baseURL = @"http://localhost/";
225       [self warnWithFormat:@"Unable to create baseURL from context!"];
226     }
227   uid = [[AgenorUserManager sharedUserManager]
228           getUIDForEmail: [_person rfc822Email]];
229
230   return ((uid)
231           ? [NSString stringWithFormat:@"%@%@", baseURL, uid]
232           : nil);
233 }
234
235 - (BOOL) sendEMailNotifications
236 {
237   return sendEMailNotifications;
238 }
239
240 - (void) sendEMailUsingTemplateNamed: (NSString *) _pageName
241                         forOldObject: (iCalRepeatableEntityObject *) _oldObject
242                         andNewObject: (iCalRepeatableEntityObject *) _newObject
243                          toAttendees: (NSArray *) _attendees
244 {
245   NSString *pageName;
246   iCalPerson *organizer;
247   NSString *cn, *sender, *iCalString;
248   NGSendMail *sendmail;
249   WOApplication *app;
250   unsigned i, count;
251   iCalPerson *attendee;
252   NSString *recipient;
253   SOGoAptMailNotification *p;
254   NSString *subject, *text, *header;
255   NGMutableHashMap *headerMap;
256   NGMimeMessage *msg;
257   NGMimeBodyPart *bodyPart;
258   NGMimeMultipartBody *body;
259
260   if ([_attendees count])
261     {
262       /* sender */
263
264       organizer = [_newObject organizer];
265       cn = [organizer cnWithoutQuotes];
266       if (cn)
267         sender = [NSString stringWithFormat:@"%@ <%@>",
268                            cn,
269                            [organizer rfc822Email]];
270       else
271         sender = [organizer rfc822Email];
272
273       /* generate iCalString once */
274       iCalString = [[_newObject parent] versitString];
275   
276       /* get sendmail object */
277       sendmail = [NGSendMail sharedSendMail];
278
279       /* get WOApplication instance */
280       app = [WOApplication application];
281
282       /* generate dynamic message content */
283
284       count = [_attendees count];
285       for (i = 0; i < count; i++)
286         {
287           attendee = [_attendees objectAtIndex:i];
288
289           /* construct recipient */
290           cn = [attendee cn];
291           if (cn)
292             recipient = [NSString stringWithFormat: @"%@ <%@>",
293                                   cn,
294                                   [attendee rfc822Email]];
295           else
296             recipient = [attendee rfc822Email];
297
298           /* create page name */
299           // TODO: select user's default language?
300           pageName = [NSString stringWithFormat: @"SOGoAptMail%@%@",
301                                mailTemplateDefaultLanguage,
302                                _pageName];
303           /* construct message content */
304           p = [app pageWithName: pageName inContext: [WOContext context]];
305           [p setNewApt: _newObject];
306           [p setOldApt: _oldObject];
307           [p setHomePageURL: [self homePageURLForPerson: attendee]];
308           [p setViewTZ: [self userTimeZone: cn]];
309           subject = [p getSubject];
310           text = [p getBody];
311
312           /* construct message */
313           headerMap = [NGMutableHashMap hashMapWithCapacity: 5];
314           
315           /* NOTE: multipart/alternative seems like the correct choice but
316            * unfortunately Thunderbird doesn't offer the rich content alternative
317            * at all. Mail.app shows the rich content alternative _only_
318            * so we'll stick with multipart/mixed for the time being.
319            */
320           [headerMap setObject: @"multipart/mixed" forKey: @"content-type"];
321           [headerMap setObject: sender forKey: @"From"];
322           [headerMap setObject: recipient forKey: @"To"];
323           [headerMap setObject: [NSCalendarDate date] forKey: @"date"];
324           [headerMap setObject: subject forKey: @"Subject"];
325           msg = [NGMimeMessage messageWithHeader: headerMap];
326
327           /* multipart body */
328           body = [[NGMimeMultipartBody alloc] initWithPart: msg];
329     
330           /* text part */
331           headerMap = [NGMutableHashMap hashMapWithCapacity: 1];
332           [headerMap setObject: @"text/plain; charset=utf-8"
333                      forKey: @"content-type"];
334           bodyPart = [NGMimeBodyPart bodyPartWithHeader: headerMap];
335           [bodyPart setBody: [text dataUsingEncoding: NSUTF8StringEncoding]];
336
337           /* attach text part to multipart body */
338           [body addBodyPart: bodyPart];
339     
340           /* calendar part */
341           header = [NSString stringWithFormat: @"text/calendar; method=%@;"
342                              @" charset=utf-8",
343                              [(iCalCalendar *) [_newObject parent] method]];
344           headerMap = [NGMutableHashMap hashMapWithCapacity: 1];
345           [headerMap setObject:header forKey: @"content-type"];
346           bodyPart = [NGMimeBodyPart bodyPartWithHeader: headerMap];
347           [bodyPart setBody: [iCalString dataUsingEncoding: NSUTF8StringEncoding]];
348
349           /* attach calendar part to multipart body */
350           [body addBodyPart: bodyPart];
351     
352           /* attach multipart body to message */
353           [msg setBody: body];
354           [body release];
355
356           /* send the damn thing */
357           [sendmail sendMimePart: msg
358                     toRecipients: [NSArray arrayWithObject: [attendee rfc822Email]]
359                     sender: [organizer rfc822Email]];
360         }
361     }
362 }
363
364 - (NSArray *) rolesOfUser: (NSString *) login
365                 inContext: (WOContext *) context
366 {
367   AgenorUserManager *um;
368   iCalRepeatableEntityObject *component;
369   NSMutableArray *sogoRoles;
370   NSString *email;
371   SOGoUser *user;
372
373   sogoRoles = [NSMutableArray new];
374   [sogoRoles autorelease];
375
376   um = [AgenorUserManager sharedUserManager];
377   email = [um getEmailForUID: login];
378
379   component = [self component];
380   if (component)
381     {
382       if ([component isOrganizer: email])
383         [sogoRoles addObject: SOGoRole_Organizer];
384       else if ([component isParticipant: email])
385         [sogoRoles addObject: SOGoRole_Participant];
386       else if ([[container ownerInContext: nil] isEqualToString: login])
387         [sogoRoles addObject: SoRole_Owner];
388     }
389   else
390     {
391       user = [[SOGoUser alloc] initWithLogin: login roles: nil];
392       [sogoRoles addObjectsFromArray: [user rolesForObject: container
393                                             inContext: context]];
394       [user release];
395     }
396
397   return sogoRoles;
398 }
399
400 @end